洛谷 P2444 [POI2000]病毒
阿新 • • 發佈:2019-01-02
題目:病毒
思路:
首先把所有病毒程式碼建成trie。
然後建出fail指標,順便完成AC自動機的優化。
然後分析樣例可以獲得這樣一棵trie圖——
3
01
11
00000
其中黑邊是trie的正常邊,綠邊是在處理AC自動機時連上的優化邊,紅邊是fail指標。
節點內部的數是節點權值,旁邊的是節點編號。
可以知道,一個無限的文字串,在AC自動機匹配的過程中一定會“死迴圈”,即存在環狀的匹配。
這在這顆trie中的體現就是存在從根節點開始的環。
要注意,這裡的環是由綠邊和黑邊構成的,即不考慮走fail指標(想一想,為什麼)。
由於這個環狀匹配不存在病毒,所以我們要找的環中一定不存在一個病毒的結尾。
且考慮AC自動機執行的過程,要從根節點開始匹配。
程式碼:
#include<bits/stdc++.h>
using namespace std;
#define maxn 2000
#define maxm 30000
#define read(x) scanf("%d",&x)
struct Trie {
int ch[maxm+5][2];
int cnt,v[maxm*2+5];
int fl[maxm*2+5];
void insert(char* x) {
int u=0,len=strlen(x);
for(int i=0; i< len; i++) {
int y=x[i]-'0';
if(!ch[u][y]) ch[u][y]=++cnt;
u=ch[u][y];
}
v[u]=true;
}
void make_fl() {
queue<int> que;
if(ch[0][0]) que.push(ch[0][0]);
if(ch[0][1]) que.push(ch[0][1]);
while(!que.empty()) {
int u=que.front();
que.pop();
for(int i=0; i<=1; i++)
if (!ch[u][i]) ch[u][i]=ch[fl[u]][i];
else {
que.push(ch[u][i]);
fl[ch[u][i]]=ch[fl[u]][i];
if(v[fl[ch[u][i]]]) v[ch[u][i]]=true;
}
}
}
} ac ;
int n;
bool vis[maxm*2+5],use[maxm*2+5];
bool dfs(int x) {
vis[x]=true;
for(int i=0;i<=1;i++) {
int y=ac.ch[x][i];
if(!y) continue;
if(vis[y]) return true;
if(use[y]||ac.v[y]) continue;
use[y]=true;
if(dfs(y)) return true;
}
vis[x]=false;
return false;
}
int main() {
read(n);
for(int i=1; i<=n; i++) {
char x[maxn+5];
scanf("%s",x);
ac.insert(x);
}
ac.make_fl();
bool ans=dfs(0);
if(ans) printf("TAK");
else printf("NIE");
return 0;
}