HDU 2457 AC自動機+DP
阿新 • • 發佈:2018-11-14
這道題好像讓我對AC自動機的失配指標有了一個新的認識。
Fail指標的求法:
Fail指標用BFS來求得,對於直接與根節點相連的節點來說,如果這些節點失配,他們的Fail指標直接指向root即可,其他節點其Fail指標求法如下:
假設當前節點為father,其孩子節點記為child。求child的Fail指標時,首先我們要找到其father的Fail指標所指向的節點,假如是t的話,我們就要看t的孩子中有沒有和child節點所表示的字母相同的節點,如果有的話,這個節點就是child的fail指標,如果發現沒有,則需要找father->fail->fail這個節點,然後重複上面過程,如果一直找都找不到,則child的Fail指標就要指向root。
這道題是問你給你N個單詞和一個字串,問你最少修改多少字元可以將字串改變成不包含任何一個單詞的字元,大概就是建出圖以後dp,dp[i][j],i表示匹配了長度為i的字串,在AC自動機上第J個節點需要修改的字元數
#include<bits/stdc++.h> using namespace std; using LL = int64_t; const int maxnode=1e6+5; const int sigma_size=4; const int INF=0x3f3f3f3f; char s[maxnode]; int dp[2005][2005]; struct Node { int son[sigma_size]; int val,fail; }ch[maxnode]; struct AC { int sz=1; queue<int>Q; void init(int x) {ch[x].fail=ch[x].val=0;memset(ch[x].son,0,sizeof(ch[x].son));} int idx(char c) { if(c=='A') return 0; if(c=='C') return 1; if(c=='T') return 2; if(c=='G') return 3; } void insert(char s[],int v) { int u=0,n=strlen(s); for(int i=0;i<n;i++) { int c=idx(s[i]); if(!ch[u].son[c]) { init(sz); ch[u].son[c]=sz++; } u=ch[u].son[c]; } ch[u].val=v; } void build() { for(int i=0;i<sigma_size;i++) if(ch[0].son[i]) Q.push(ch[0].son[i]); while(!Q.empty()) { int now=Q.front();Q.pop(); int fail=ch[now].fail; for(int i=0;i<sigma_size;i++) { int nxt=ch[now].son[i]; if(nxt) { ch[nxt].fail=ch[fail].son[i]; Q.push(nxt); } else ch[now].son[i]=ch[fail].son[i]; ch[ch[now].son[i]].val|=ch[ch[ch[now].fail].son[i]].val; } } } int solve(char s[]) { int len=strlen(s),ans=INF; for(int i=0;i<=len;i++) { for(int j=0;j<sz;j++) { dp[i][j]=INF; } } dp[0][0]=0; for(int i=1;i<=len;i++) { for(int j=0;j<sz;j++) { for(int k=0;k<4;k++) { if(ch[ch[j].son[k]].val!=1) { if(idx(s[i-1])==k) dp[i][ch[j].son[k]]=min(dp[i][ch[j].son[k]],dp[i-1][j]); else dp[i][ch[j].son[k]]=min(dp[i][ch[j].son[k]],dp[i-1][j]+1); } } } } for(int i=0;i<sz;i++) ans=min(dp[len][i],ans); if(ans==INF) ans=-1; return ans; } }; int main() { ios::sync_with_stdio(0); cin.tie(0); int n,kase=1; while(cin>>n&&n) { AC ans;ans.init(0); for(int i=1;i<=n;i++) { cin>>s;ans.insert(s,1); } ans.build(); cin>>s; cout<<"Case "<<kase++<<": "<<ans.solve(s)<<"\n"; } return 0; }