【[POI2000]病毒】
阿新 • • 發佈:2019-01-02
\(Ac\)自動機好題了
這個題要求我們一直無法匹配到結束標記,所以我們直接在\(trie\)圖上找到一個環,這個環可以被根節點到達,之後還沒有結束標記
發現自己不會\(dfs\)找環,於是直接莽上\(tarjan\)
之後一直寫掛各種\(sb\)
程式碼
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<queue> #define re register #define LL long long #define maxn 30005 #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) struct E{int v,nxt;}e[maxn<<4]; int head[maxn]; int n,m,cnt,top,tot,p,num,mid; char S[maxn]; int son[maxn][2],fail[maxn],flag[maxn]; int dfn[maxn],low[maxn],f[maxn],st[maxn],col[maxn],d[maxn],vis[maxn]; inline void ins() { scanf("%s",S+1); int len=strlen(S+1),now=0; for(re int i=1;i<=len;i++) {if(!son[now][S[i]-'0']) son[now][S[i]-'0']=++cnt;now=son[now][S[i]-'0'];} flag[now]=1; } inline void Build() { std::queue<int> q; for(re int i=0;i<2;i++) if(son[0][i]) q.push(son[0][i]); while(!q.empty()) { int k=q.front();q.pop(); flag[k]|=flag[fail[k]]; for(re int i=0;i<2;i++) if(son[k][i]) fail[son[k][i]]=son[fail[k]][i],q.push(son[k][i]); else son[k][i]=son[fail[k]][i]; } } void tarjan(int x) { if(flag[x]) return; f[x]=1,st[++top]=x,dfn[x]=low[x]=++tot; for(re int i=0;i<2;i++) { if(flag[son[x][i]]) continue; if(!dfn[son[x][i]]) tarjan(son[x][i]),low[x]=min(low[x],low[son[x][i]]); else if(f[son[x][i]]) low[x]=min(low[x],dfn[son[x][i]]); } if(dfn[x]==low[x]) { ++p;int t=0; do {mid=st[top--];f[mid]=0,t++,col[mid]=p;}while(x!=mid); d[p]=t; } } inline void add_edge(int x,int y){e[++num].v=y,e[num].nxt=head[x],head[x]=num;} int dfs(int x) { if(d[x]>1) return 1; int ff=0; vis[x]=1; for(re int i=head[x];i;i=e[i].nxt) if(!vis[e[i].v]) ff|=dfs(e[i].v); return ff; } int main() { scanf("%d",&n); for(re int i=1;i<=n;i++) ins();Build(); for(re int i=0;i<=cnt;i++) if(!dfn[i]) tarjan(i); for(re int i=0;i<=cnt;i++) for(re int j=0;j<2;j++) if(col[son[i][j]]!=col[i]) add_edge(col[i],col[son[i][j]]); for(re int i=0;i<=cnt;i++) for(re int j=0;j<2;j++) if(son[i][j]==i) d[col[i]]++; vis[0]=1; if(dfs(col[0])) puts("TAK");else puts("NIE"); return 0; }