版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/yqdjl6/article/details/83082773
这道题好像让我对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;
}