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;
}