ac自动机

ac自动机

解决的问题 :

在一个文本串中查找多个模式串.

模板

https://www.luogu.com.cn/problem/P3808

int n,ans;
char s[N];

bool vis[N];
int tr[N][26];
int endd[N];

struct Trie {
	int sz;
	Trie() {
		sz=1;
		memset(tr[0],0,sizeof(tr[0]));
		memset(vis,0,sizeof(vis));
	}

	void insert(char *s) {
		int u =0,n=strlen(s);
		for(int i=0; i<n; i++) {
			int c = s[i] - 'a';
			if(!tr[u][c]) {
				memset(tr[sz],0,sizeof(tr[sz]));
				endd[sz] = 0;
				tr[u][c]=sz++;
			}
			u = tr[u][c];

		}
		endd[u]++;
	}
};

int last[N],f[N];

void print(int j) {
	if(j && !vis[j]) {
		ans += endd[j];
		vis[j] = 1;
		print(last[j]);
	}
}
void build() {
	queue<int>q;
	f[0] = 0;
	for(int i=0; i<26; i++) {
		int u = tr[0][i];
		if(u) {
			f[u] =0,last[u]=0,q.push(u);
		}
	}
	while(!q.empty()) {
		int r=q.front();
		q.pop();
		for(int c=0; c<26; c++) {
			int u = tr[r][c];
			if(!u) {
				tr[r][c] = tr[f[r]][c];
				continue;
			}
			q.push(u);
			int v =f[r];
			while(v && !tr[v][c])v = f[v];
			f[u] = tr[v][c];
			last[u] = endd[f[u]]?f[u]:last[f[u]];
		}
	}
}

void find(char *s){
	int n = strlen(s);
	int j =0;
	for(int i=0;i<n;i++){
		int c = s[i] - 'a';
		j = tr[j][c];
		if(endd[j])print(j);
		else if(last[j])print(last[j]); 
	}
}

void work() {
	scanf("%d",&n);
	Trie trie;
	ans = 0;
	for(int i=1;i<=n;i++){
		scanf("%s",s);
		trie.insert(s);
	}
	build();
	scanf("%s",s);
	find(s);
	printf("%d\n",ans); 
}

查找文章中最多的模块串

https://www.luogu.com.cn/problem/P3796

int n,ans;
char s[N][155];

bool vis[N];
int tr[N][26];
int endd[N];
int id[N];

int num[N];

struct Trie {
	int sz;
	Trie() {
		sz=1;
		memset(tr[0],0,sizeof(tr[0]));
		memset(vis,0,sizeof(vis));
	}

	void insert(char *s,int fa) {
		int u =0,n=strlen(s);
		for(int i=0; i<n; i++) {
			int c = s[i] - 'a';
			if(!tr[u][c]) {
				memset(tr[sz],0,sizeof(tr[sz]));
				endd[sz] = 0;
				tr[u][c]=sz++;
			}
			u = tr[u][c];

		}
		endd[u]++;
		id[u] = fa;  //u这个结点对应fa字符串
	}
};

int last[N],f[N];

void print(int j) {
	if(j && !vis[j]) {
		ans += endd[j];
		num[id[j]]++;  //记录个数
//		vis[j] = 1;
		print(last[j]);
	}
}
void build() {
	queue<int>q;
	f[0] = 0;
	for(int i=0; i<26; i++) {
		int u = tr[0][i];
		if(u) {
			f[u] =0,last[u]=0,q.push(u);
		}
	}
	while(!q.empty()) {
		int r=q.front();
		q.pop();
		for(int c=0; c<26; c++) {
			int u = tr[r][c];
			if(!u) {
				tr[r][c] = tr[f[r]][c];
				continue;
			}
			q.push(u);
			int v =f[r];
			while(v && !tr[v][c])v = f[v];
			f[u] = tr[v][c];
			last[u] = endd[f[u]]?f[u]:last[f[u]];
		}
	}
}

void find(char *s) {
	int n = strlen(s);
	int j =0;
	for(int i=0; i<n; i++) {
		int c = s[i] - 'a';
		j = tr[j][c];
		if(endd[j])print(j);
		else if(last[j])print(last[j]);
	}
}

void work() {
	while(~scanf("%d",&n) && n) {
		Trie trie;
		for(int i=0; i<n; i++) {
			scanf("%s",s[i]);
			trie.insert(s[i],i);
			num[i] = 0;
		}
		build();
		scanf("%s",s[n]);
		find(s[n]);

		int maxn = 0;
		for(int i=0; i<n; i++) {
			if(num[i] > maxn){
				maxn = num[i];
			} 
		}
		printf("%d\n",maxn);
		for(int i=0;i<n;i++){
			if(num[i] == maxn){
				printf("%s\n",s[i]);
			}
		}
	}
}
上一篇:Valley Numer II(状压dp)


下一篇:Kuangbin 专题六 最小生成树