【AC自動機】地圖匹配

hz2016評測《《點擊訪問《《增加了內存

caioj《《點擊訪問

這題其實還是模版題吧,說難不難,說不難還是很難。

我們不能按照暴力的思想,給圖for8個方向建樹。

這樣會超時的。

所以悲傷的我們只好測試可不可以反着建。

最後我們總結出反着建句子的字典樹,然後離線找匹配。

例如一個5*5的地圖
11111
12221
12321
12221
11111
先在1號的點向八個方向去字符樹裏面匹配 然後就是2的點,最後3號點,總會匹配到適合的字符串。 所以這題就解出來了。
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxchar 1000000
#define Maxm 1000
#define Maxn 1000
#define Maxs 26
#define mes(x,y) memset(x,y,sizeof(x));
#define mpy(x,y) memcpy(x,y,sizeof(x))
#define INF 2147483647
using namespace std;
const int dx[8]={-1,-1,0,1,1,1,0,-1};
const int dy[8]={0,1,1,1,0,-1,-1,-1};
struct Tire{
	int s,fail,c[Maxs+1];
	bool v;
	void clear(){
		s=fail=0;v=false;
		mes(c,-1);
	}
}tr[Maxm*Maxm+1];
int tot;
char s[Maxn+1];
struct node{
	int x,y,w;
}a[Maxn+1];
map<int, map<int,int> >qt;
void add(int root,int p) {
	int x=root,len=strlen(s+1);
	for(int i=len;i>=1;i--){
		int y=s[i]-'A'+1;
        if(tr[x].c[y]==-1){
			tr[x].c[y]=++tot;
			tr[tot].clear();
		}
		x=tr[x].c[y];
	}
	tr[x].s=p;
}
queue<int> q;
void build_fail(){
	int x,y,son;
	q.push(0);
	while(q.empty()==false) {
		x=q.front();
		for(int i=1;i<=26;i++){
			son=tr[x].c[i];
			if(son==-1)continue;
			if(x==0)tr[son].fail=0;
			else{
				int j=tr[x].fail;
				while(j>0&&tr[j].c[i]==-1)j=tr[j].fail;
				tr[son].fail=max(tr[j].c[i],0);
			}
			q.push(son);
		}
		q.pop();
	}
}
int n,m,member;
char maps[Maxm+1][Maxm+1];
inline bool check(int x,int y){
	if(x>=1&&x<=n&&y>=1&&y<=m)return true;
	return false;
}
void Find(int x,int y,int w){
	int m=0;
	while(check(x,y)==true){
		int j=maps[x][y]-'A'+1;
		while(m!=0&&tr[m].c[j]==-1)m=tr[m].fail;
		if(tr[m].c[j]!=-1)m=tr[m].c[j];
		for(int k=m;k!=0&&tr[k].v==false;k=tr[k].fail){
			if(tr[k].s>0){
				int l=tr[k].s;
				a[l].x=x;
				a[l].y=y;
				a[l].w=(w+4)%8;
			}
			tr[k].v=true;
		}
		x+=dx[w];
		y+=dy[w];
	}
}
int main(){
	scanf("%d%d%d",&n,&m,&member);
	tr[0].clear();
	tot=0;
	for(int i=1;i<=n;i++)scanf("%s",maps[i]+1);
	for(int i=1;i<=member;i++){
		scanf("%s",s+1);
		add(0,i);
	}
	build_fail();
	for(int i=1;i<=n;i++)Find(i,1,1),Find(i,1,2),Find(i,1,3),Find(i,m,5),Find(i,m,6),Find(i,m,7);
	for(int j=1;j<=m;j++)Find(1,j,3),Find(1,j,4),Find(1,j,5),Find(n,j,0),Find(n,j,1),Find(n,j,7);
	for(int i=1;i<=member;i++)printf("%d %d %c\n",a[i].x-1,a[i].y-1,a[i].w+'A');
	return 0;
}
 

查看原文:http://hz2016.tk/blog/?p=41
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章