POJ 3691 DNA repair(自动机DP)

题意:先给出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;
}

 

posted @ 2012-08-08 19:30  BeatLJ  阅读(317)  评论(0编辑  收藏  举报