http://acm.hdu.edu.cn/showproblem.php?pid=2457
题意: 给出了一些病毒串的基因, 又给出了一个基因串,问至少修改多少个基因串中的字符可以不含病毒串。
首先把病毒建立一个自动机。
dp[i][j]表示 长度为i的字符串以状态j结尾时,最少修改数
dp[0][0]=0,其他无穷
那么dp[i][j]可以用 dp[i-1][k]也就是长度为i-1时,状态为k的节点转移过来,
转移的条件是,k本身不是病毒节点,且k的后继节点j也不是病毒节点
最后扫描dp[n][i],如果为inf表示无法转到此状态
取min值即是答案
dp为1000*1000
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const int maxlen=1000+50;
const int maxn=1005;
const int all_size=4;
int trie[maxn][all_size];
int fail[maxn];
int tag[maxn];
int sz;
queue<int >Q;
int n;
struct Aho
{
int root;
int newnode()//静态创建新节点
{
memset(trie[sz],-1,sizeof trie[sz]);
tag[sz]=0;
sz++;
return sz-1;
}
void init()//初始化
{
sz=0;
newnode();
}
void insert(char s[],int id) //插入字符串构建ac自动机,构建trie树
{
int len=strlen(s),p=0;;
for (int i=0; i<len; i++)
{
int id=s[i]-'0';
if (trie[p][id]==-1)
trie[p][id]=newnode();
p=trie[p][id];
}
tag[p]=id; //结束标记
}
void getfail() //构建自动机fail指针
{
while(!Q.empty()) Q.pop();
fail[root]=root; //root指向root
for (int i=0; i<all_size; i++)
{
if (trie[root][i]==-1)//第一个字符不存在,指向root
trie[root][i]=root;
else //第一个字符的fail指针指向root
{
fail[trie[root][i]]=root;
Q.push(trie[root][i]); //并放入队列,待bfs扩展
}
}
while(!Q.empty())
{
int u=Q.front(); //取扩展节点
Q.pop();
if(tag[fail[u]]) tag[u]=1; //***如果之前是tag,直接标记
for (int i=0; i<all_size; i++)//遍历所有子节点
{
if (trie[u][i]==-1)//如果不存在,则子节点直接指向fail[u]节点的对应子节点
trie[u][i]=trie[fail[u]][i];
else //如果存在,则该节点的fail指针指向fail[u]节点对应的子节点
{
fail[trie[u][i]]=trie[fail[u]][i];
Q.push(trie[u][i]); //继续扩展
}
}
}
}
} aho;
char ss[maxlen];
char cop[maxlen];
char name[55][25];
void change(char *ss)
{
int len=strlen(ss);
for (int i=0; i<len; i++)
if (ss[i]=='A') ss[i]='0'+0;
else if (ss[i]=='T')ss[i]='0'+1;
else if (ss[i]=='C')ss[i]='0'+2;
else if (ss[i]=='G')ss[i]='0'+3;
}
int dp[1005][1005];
const int inf=1e6;
int main()
{
int cnt=1;
while(cin>>n&&n)
{
aho.init();
for (int i=0; i<n; i++)
{
scanf("%s",name[i]);
int len=strlen(name[i]);
change(name[i]);
aho.insert(name[i],i+1);
}
aho.getfail();
scanf("%s",ss);
change(ss);
int len=strlen(ss);
for (int i=0; i<=len; i++)
for (int j=0; j<sz; j++)
dp[i][j]=inf;
dp[0][0]=0;
for (int L=1; L<=len; L++)
{
for (int i=0; i<sz; i++)
{
if (tag[i])continue;
if (dp[L-1][i]==inf) continue;
int id=ss[L-1]-'0';
for (int j=0; j<all_size; j++)
{
if (tag[trie[i][j]])continue;
int add=(j!=id);
dp[L][trie[i][j]]=min(dp[L][trie[i][j]],
dp[L-1][i]+add);
}
int cc;
}
}
int ans=inf;
for (int i=0; i<sz; i++)
ans=min(ans,dp[len][i]);
printf("Case %d: ",cnt++);
if (ans==inf)
printf("-1\n");
else
printf("%d\n",ans);
}
return 0;
}