hdu 2457&poj 3691 DNA repair ACオートマチック+DP
3995 ワード
やってみたら1 Aだったなんて...感動しました....まずn個のウイルスDNA配列を与え,もう一つの長い列を与えた.長さの文字列を少なくともいくつか変更して、ウイルスのシーケンスを1つも含まないようにします.ウイルスの配列を持つACオートマトンを構築し、その後オートマトンでDPを行い、現在の長さがl、オートマトン上の状態がiの場合、最小の文字修正数をdp[l][i]で表す.サイクルA,T,G,Cの4つのスキームは,この文字を追加した後の状態が安全であることを前提として,現在のスキームと親列のl番目がちょうど同じであれば,dp[l+1][tree[i][A,T,G,C]]の最小値を直接dp[l][i]+1で更新し,そうでなければ現在位置の文字を修正する必要があり,すなわちdp[l][i]+1でdp[l+1][tree[i][A,T,G,C]]を更新する.dpの初期値はいずれもinf,dp[0][i],iが安全状態の場合は0とする.ループして、最後にdp[len][i]から最小値を探して出力すればいいです.最小値がなければ解けません.出力-1です.
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <string>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=1020;
const int tk=4;
int tree[maxn][tk];
int val[maxn];
int last[maxn];
int f[maxn];
bool no[maxn];
int n,m,p,q,r,k,t,tt;
int top;
int dp[maxn][maxn];
inline int idx(char s)
{
if (s=='A') return 0;
if (s=='T') return 1;
if (s=='G') return 2;
if (s=='C') return 3;
}
struct autoAC
{
void init()
{
top=1;
memset(tree[0],0,sizeof tree[0]);
memset(val,0,sizeof val);
memset(f,0,sizeof f);
memset(last,0,sizeof last);
memset(no,false,sizeof no);
}
void insert(char* s,int rank=1)
{
int rt,nxt;
for (rt=0; *s; rt=nxt,++s)
{
nxt=tree[rt][idx(*s)];
if (nxt==0)
{
tree[rt][idx(*s)]=nxt=top;
memset(tree[top],0,sizeof tree[top]);
top++;
}
}
val[rt]=rank;
}
void getFail()
{
queue<int> q;
f[0]=0;
for (int c=0; c<tk; c++)
{
int u=tree[0][c];
if (u)
{
q.push(u);
f[u]=0;
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();
q.pop();
for (int c=0;c<tk; c++)
{
int u=tree[r][c];
if (!u)
{
tree[r][c]=tree[f[r]][c];
continue;
}
q.push(u);
int v=f[r];
while(v && !tree[v][c]) v=f[v];
f[u]=tree[v][c];
last[u]=val[f[u]]?f[u]:last[f[u]];
}
}
}
void pushdown()
{
for (int i=0; i<top; i++)
{
int j=i;
while(j)
{
no[i]|=val[j];
j=last[j];
}
}
}
}ac;
char s[30],ss[30],str[1050];
int main()
{
tt=0;
// freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
while(~scanf("%d
",&n) && n)
{
tt++;
ac.init();
for (int i=1; i<=n; i++)
{
scanf("%s
",s);
ac.insert(s,1);
}
ac.getFail();
ac.pushdown();
scanf("%s
",str);
memset(dp,0x3f3f3f,sizeof dp);
int nxt;
int len=strlen(str);
for (int i=0; i<top; i++)
if (!no[i]) dp[0][i]=0;
for (int l=0; l<len; l++)
for (int i=0; i<top; i++)
if (no[i]) continue;
else for (int c=0; c<4;c++)
{
nxt=tree[i][c];
if (no[nxt]) continue;
if (idx(str[l])==c) dp[l+1][nxt]=min(dp[l+1][nxt],dp[l][i]);
else dp[l+1][nxt]=min(dp[l+1][nxt],dp[l][i]+1);
}
int res=99999;
printf("Case %d: ",tt);
for (int i=0; i<top; i++)
res=min(dp[len][i],res);
if (res<99999)printf("%d
",res);
else printf("-1
");
}
return 0;
}