http://acm.split.hdu.edu.cn/showproblem.php?pid=2457
大体思路就是说 :
对给定的字符串(病毒串)构造AC机,标记每个病毒串的末尾,并在构造fail指针时 如果当前节点的失败指针是病毒串那么当前节点也作为标记。 因为 AC机的状态转移会使得当前节点转移到失败指针所指向的节点中来。
之后把给你的串(匹配串)进行DP,假设DP初始值最大 MME(dp,inf) ,并设dp[0][0]=0;那么dp[i][j] 表示为 长为 i 的串如果走到了第 j 个状态那么有多少种方法。那么每次遇到病毒串要跳过,每个状态为INF时也要跳过,表明到达当前这个长度的第j个状态之前没有经历过 因为只有一个串,那么他所经过的状态一定是一样的。
之后到达 j 状态后枚举每个子节点,同样跳过所有病毒串,那么当增加了一个长度之后到达了另一个新状态后所得到的dp[i+1][当前j状态的某个儿子的状态] 就为 min(dp[i+1][[当前j状态的某个儿子的状态],dp[i][j](去掉当前节点之后判断当前节点是否需要改变,如果当前节点与你j状态此时的儿子一样不需要改变,如不一样则需要改变一次,那么dp[i][j]+1;
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <queue>
#define maxs 1050
#define MME(i,j) memset(i,j,sizeof(i))
#define inf 0x3f3f3f3f
using namespace std;
int id['Z'+1];
char s[maxs];
int dp[maxs][maxs];
void setid()
{
id['A']=0;
id['G']=1;
id['C']=2;
id['T']=3;
}
struct node
{
int nexts[maxs][4],fail[maxs],ends[maxs];
int root,L;
int newnode()
{
for(int i=0;i<4;i++) nexts[L][i]=-1;
ends[L++]=0;
return L-1;
}
// Rt
void init() { L=0; root=newnode();MME(fail,0); MME(ends,0);}
void Insert(char *s)
{
int len=strlen(s),idex,now=root;
for(int i=0;i<len;i++)
{
idex=id[s[i]];
if(nexts[now][idex]==-1)
nexts[now][idex]=newnode();
now=nexts[now][idex];
}
ends[now]=1;// 标记该点为 疾病 DNA
}
void build()
{
queue<int>Q;
fail[root]=root;
for(int i=0;i<4;i++)
{
if(nexts[root][i]==-1)
nexts[root][i]=root;
else{
fail[nexts[root][i]]=root;
Q.push(nexts[root][i]);
}
}
int now;
while(!Q.empty())
{
now=Q.front();
if(ends[ fail[ now ] ])
ends[ now ]=1;
Q.pop();
for(int i=0;i<4;i++)
{
if( nexts[now][i]==-1 )
nexts[now][i] = nexts[fail[now]][i];
else
{
fail[ nexts[now][i] ] =nexts[fail[now]][i];
Q.push(nexts[now][i]);
}
}
}
}
int DP(char *s)
{
MME(dp,inf);
// printf("%d\n",dp[1][1]);
dp[0][0]=0;
int len=strlen(s);
for( int i=0;i<len;i++ )
{
for( int j=0;j<L;j++ )
{
if( ends[j] ) continue;
if(dp[i][j]==inf ) continue;
for(int ch=0;ch<4;ch++)
{
int &temp=nexts[j][ch];
if( ends[temp] ) continue;
dp[i+1][temp] = min(dp[i+1][temp],dp[i][j] + (id[s[i]]!=ch) );
}
}
}
int ans=inf;
for(int i=0; i<L; i++)
{
ans=min(ans,dp[len][i]);
}
return ans == inf?-1:ans;
}
}AC;
int main()
{
int n,cas=1;
setid();
while(~scanf("%d",&n) && n)
{
AC.init();
for(int i=0;i<n;i++)
{
scanf("%s",s);
AC.Insert(s);
}
AC.build();
// puts("*/*/*/");
scanf("%s",s);
int ans=AC.DP(s);
//puts("**************");
printf("Case %d: %d\n", cas ++, ans );
}
return 0;
}