1. 程式人生 > >[POI2000] 病毒

[POI2000] 病毒

所有 code pro 額外 com ans str amp int

洛谷 P2444 傳送門

bzoj 2938 傳送門

AC自動機的題。

很顯然的操作是對所有串建一個AC自動機。

然後我們模擬匹配的過程。

如果能從根開始,一直匹配而不遇到終止節點,那麽就找到了一個解。

也就是說,我們的目標是尋找一個根節點能到達的環。

那就在Trie圖上DFS就行了。

如果只有in標記,洛谷上能A,lnsyoj上會T三個點。

我們需要額外記錄一個v,避免對已經搜過的點再次搜索。

註意,某個點的end要繼承他的fail指向的節點的end。

 1 #include<cstdio>
 2 #include<cstring>
 3
#include<queue> 4 using std::queue; 5 6 int n,sz; 7 int s[30005][2],ed[30005],fal[30005]; 8 char a[30005]; 9 10 void insert() 11 { 12 scanf("%s",a+1); 13 int l=strlen(a+1); 14 int p=0; 15 for(int i=1;i<=l;i++) 16 { 17 int c=a[i]-0; 18 if(!s[p][c])s[p][c]=++sz;
19 p=s[p][c]; 20 } 21 ed[p]=1; 22 } 23 24 void build() 25 { 26 queue<int>qq; 27 for(int i=0;i<=1;i++)qq.push(s[0][i]); 28 while(!qq.empty()) 29 { 30 int p=qq.front(); 31 qq.pop(); 32 for(int i=0;i<=1;i++) 33 { 34 if
(s[p][i]) 35 { 36 fal[s[p][i]]=s[fal[p]][i]; 37 ed[s[p][i]]|=ed[fal[s[p][i]]]; 38 qq.push(s[p][i]); 39 } 40 else s[p][i]=s[fal[p]][i]; 41 } 42 } 43 } 44 45 int ans,in[30005],v[30005]; 46 47 void dfs(int p) 48 { 49 if(in[p]){ans=1;return;} 50 if(v[p]||ed[p]||ans)return; 51 in[p]=v[p]=1; 52 for(int i=0;i<=1;i++)dfs(s[p][i]); 53 in[p]=0; 54 } 55 56 int main() 57 { 58 scanf("%d",&n); 59 for(int i=1;i<=n;i++)insert(); 60 build(); 61 dfs(0); 62 printf(ans?"TAK":"NIE"); 63 return 0; 64 }

[POI2000] 病毒