现在的位置: 首页 > 综合 > 正文

【AC自动机+DP】 hdu3691 DNA repair

2018年01月14日 ⁄ 综合 ⁄ 共 1767字 ⁄ 字号 评论关闭

DNA repair

题目:http://poj.org/problem?id=3691

题意:就是给定N个病毒串,然后给定一个主串,然后求出修改主串多少次使得该串不包含病毒串。

题解:AC自动机+DP。首先是AC自动机的空指针要修改下,不能为空,也需要指向字典树里面的结点,为了之后在字典树上DP,然后建立fail指针。

dp(i,j)表示主串匹配到第i位时在自动机上的状态为j时的最少修改次数

代码:

#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
#define MAX 1005
#define min(a,b) ((a)<(b)?(a):(b))
int indx(char c)
{
    switch(c)
    {
    case 'A':
        return 0;
    case 'G':
        return 1;
    case 'C':
        return 2;
    case 'T':
        return 3;
    }
}
struct node
{
    int next[4],fail;
} head[MAX];
int dp[MAX][MAX];
bool danger[MAX];
int cnt=1;
void build(char *s,int idx)
{
    int len=strlen(s),k;
    for(int i=0; i<len; ++i)
    {
        k=indx(s[i]);
        if(head[idx].next[k]==0)
            head[idx].next[k]=(cnt++);
        idx=head[idx].next[k];
        if(danger[idx]) break;
    }
    danger[idx]=true;
}
void build_fail(int idx)
{
    int now;
    queue<int> q;
    head[idx].fail=0;
    q.push(idx);
    for(; !q.empty();)
    {
        now=q.front();
        q.pop();
        for(int i=0; i<4; ++i)
            if(head[now].next[i])
            {
                if(now==0) head[head[now].next[i]].fail=0;
                else       head[head[now].next[i]].fail=head[head[now].fail].next[i];
                if(danger[head[head[now].next[i]].fail])
                    danger[head[now].next[i]]=true;//如果fail节点是危险的,那么本节点也是危险的(重要)
                q.push(head[now].next[i]);
            }
            else
            {
                if(now==0) head[now].next[i]=0;
                else       head[now].next[i]=head[head[now].fail].next[i];
            }
    }
}
int main()
{
    int n;
    char s[MAX];
    for(int cas=1; scanf("%d",&n),n;)
    {
        cnt=1;
        memset(head,0,sizeof(head));
        memset(danger,false,sizeof(danger));
        for(; n--;)
        {
            scanf("%s",s);
            build(s,0);
        }
        build_fail(0);
        scanf("%s",s);
        int w,len=strlen(s);
        for(int i=0;i<=len;++i)
            for(int j=0;j<=cnt;++j)
                dp[i][j]=0xfffff;
        dp[0][0]=0;
        for(int i=1; i<=len; ++i)
        {
            w=indx(s[i-1]);
            for(int j=0; j<cnt; ++j)
                for(int k=0; k<4; ++k)
                {
                    int idx=head[j].next[k];
                    if(danger[idx]) continue;
                    dp[i][idx]=min(dp[i][idx],dp[i-1][j]+(k!=w));
                }
        }
        int ans=0xfffff;
        for(int i=0; i<cnt; ++i)
            if(!danger[i])
                ans=min(ans,dp[len][i]);
        if(ans==0xfffff) ans=-1;
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}

来源:http://blog.csdn.net/acm_ted

抱歉!评论已关闭.