您的位置:首页 > 大数据 > 人工智能

POJ 3691 DNA repair(自动机DP)

2012-08-08 19:30 337 查看
题意:先给出m个DNA片段(含致病基因),然后给一个长为n的DNA序列,求最少需要修改多少次,使得这个DNA序列不含致病基因。修改操作定义为将DNA中某个碱基变为另一个碱基,如将A变为G

数据范围:1<=m<=50,1<=n<=1000

分析:先建自动机,然后DP。

状态设计:dp[i][j]为从根结点出发走 i 步后到达状态 j 最少需要修改的次数。

状态转移:

1、dp[i][j]=MIN(dp[i-1][k]),从状态k能根据s[i]跳到状态j,无需修改;

2、dp[i][j]=MIN(dp[i-1][k])+1,从状态k不能根据s[i]跳到状态j,需要修改s[i]。(注意区分DP的状态和自动机的状态)

初始化:dp[0][0]=0,其余的dp[0][i]=INF.

View Code

#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define N 51
#define LEN 21
#define INF 0x3f3f3f3f
#define MIN(a,b) ((a)<(b)?(a):(b))
int next[N*LEN][4];
int fail[N*LEN];
bool flag[N*LEN];
int n,node;
int dp[1010][N*LEN];
char s[1010];
int len;
void init()
{
node=1;
memset(next[0],0,sizeof(next[0]));
}
void add(int cur,int k)
{
memset(next[node],0,sizeof(next[node]));
flag[node]=0;
next[cur][k]=node++;
}
int hash(char c)
{
switch(c)
{
case 'A':
return 0;
case 'C':
return 1;
case 'G':
return 2;
case 'T':
return 3;
}
}
void insert(char *s)
{
int i,cur,k;
for(i=cur=0; s[i]; i++)
{
k=hash(s[i]);
if(!next[cur][k])   add(cur,k);
cur=next[cur][k];
}
flag[cur]=1;
}
void build_ac()
{
queue<int>q;
int cur,nxt,tmp;

fail[0]=0;
q.push(0);

while(!q.empty())
{
cur=q.front(),q.pop();
for(int k=0; k<4; k++)
{
nxt=next[cur][k];
if(nxt)
{
if(!cur)    fail[nxt]=0;
else
{
for(tmp=fail[cur]; tmp && !next[tmp][k]; tmp=fail[tmp]);
fail[nxt]=next[tmp][k];
}
if(flag[fail[nxt]]) flag[nxt]=1;
q.push(nxt);
}
else    next[cur][k]=next[fail[cur]][k];
}
}
}
void solve()
{
memset(dp,0x3f,sizeof(dp));
dp[0][0]=0;

len=strlen(s+1);
for(int step=1; step<=len; step++)
{
for(int pre=0; pre<node; pre++)
{
if(flag[pre])   continue;
for(int k=0; k<4; k++)
{
int cur=next[pre][k];
if(hash(s[step])==k)
{
dp[step][cur]=MIN(dp[step-1][pre],dp[step][cur]);
}
else
{
dp[step][cur]=MIN(dp[step-1][pre]+1,dp[step][cur]);
}
}
}
}
int ans=INF;
for(int state=0; state<node; state++)
{
if(!flag[state])
{
ans=MIN(ans,dp[len][state]);
}
}
if(ans<INF) printf("%d\n",ans);
else    puts("-1");
}
int main()
{
int kase=0;
while(scanf("%d",&n),n)
{
init();
for(int i=0; i<n; i++)
{
scanf("%s",s);
insert(s);
}
scanf("%s",s+1);
build_ac();
printf("Case %d: ",++kase);
solve();
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: