题意:
给N个单词,再给一个串str (只含A、G、C、T)
问对于str要至少修改几个字符能不含有N个单词
思路:
建立trie图,做自动机dp
dp[i][j] 代表走过str的i个字母在j节点至少需要修改几个字符
trie *p=node[j]->next[k]; if(p->mark) continue; //不可达 dp[i][p->id]=min(dp[i][p->id],dp[i-1][j]+(getid(fuck[i])!=k));就是第i步从节点j走到对应的k,如果k不是这步的字母就修改,取最小值。
最后遍历长度为len时每个节点的情况,取最小值。
代码:
#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
#include"string"
#define inf 9999999
using namespace std;
int triecont;
struct trie
{
int mark,id;
trie *next[5],*fail;
trie()
{
memset(next,0,sizeof(next));
fail=NULL;
mark=id=0;
}
};
trie *root,*node[1234];
int getid(char x)
{
if(x=='A') return 0;
else if(x=='C') return 1;
else if(x=='G') return 2;
return 3;
}
void init(char *v)
{
trie *p=root;
for(int i=0;v[i];i++)
{
int tep=getid(v[i]);
if(p->next[tep]==NULL)
{
p->next[tep]=new trie();
node[triecont]=p->next[tep];
p->next[tep]->id=triecont++;
}
p=p->next[tep];
}
p->mark=1;
}
void getac()
{
queue<trie*>q;
q.push(root);
while(!q.empty())
{
trie *p=q.front();
q.pop();
for(int i=0;i<4;i++)
{
if(p->next[i]==NULL)
{
if(p==root) p->next[i]=root;
else p->next[i]=p->fail->next[i];
}
else
{
if(p==root) p->next[i]->fail=root;
else p->next[i]->fail=p->fail->next[i];
q.push(p->next[i]);
if(p!=root) p->next[i]->mark|=p->fail->next[i]->mark;
}
}
}
}
int dp[1234][1234];
char fuck[1234];
int main()
{
int n;
int cas=1;
while(scanf("%d",&n),n)
{
triecont=0;
root=new trie();
node[triecont]=root;
root->id=triecont++;
while(n--)
{
char x[33];
scanf("%s",x);
init(x);
}
getac();
scanf("%s",fuck+1);
int len=strlen(fuck+1);
for(int i=0;i<=len;i++) for(int j=0;j<triecont;j++) dp[i][j]=inf;
dp[0][0]=0;
for(int i=1;i<=len;i++)
{
for(int j=0;j<triecont;j++)
{
if(dp[i-1][j]==inf) continue;
for(int k=0;k<4;k++)
{
trie *p=node[j]->next[k];
if(p->mark) continue;
dp[i][p->id]=min(dp[i][p->id],dp[i-1][j]+(getid(fuck[i])!=k));
}
}
}
int ans=inf;
for(int i=0;i<triecont;i++) ans=min(ans,dp[len][i]);
printf("Case %d: %d\n",cas++,ans==inf?-1:ans);
}
return 0;
}