[AC自动机+dp] hdu 2457 DNA repair

题意:

给N个单词,再给一个串str (只含A、G、C、T)

问对于str要至少修改几个字符能不含有N个单词

思路:

建立trie图,做自动机dp

dp[i][j] 代表走过str的i个字母在j节点至少需要修改几个字符

 trie *p=node[j]->next[k];
 if(p->mark) continue;   //不可达
 dp[i][p->id]=min(dp[i][p->id],dp[i-1][j]+(getid(fuck[i])!=k));

就是第i步从节点j走到对应的k,如果k不是这步的字母就修改,取最小值。

最后遍历长度为len时每个节点的情况,取最小值。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
#include"map"
#include"string"
#define inf 9999999
using namespace std;
int triecont;
struct trie
{
    int mark,id;
    trie *next[5],*fail;
    trie()
    {
        memset(next,0,sizeof(next));
        fail=NULL;
        mark=id=0;
    }
};
trie *root,*node[1234];
int getid(char x)
{
    if(x=='A') return 0;
    else if(x=='C') return 1;
    else if(x=='G') return 2;
    return 3;
}
void init(char *v)
{
    trie *p=root;
    for(int i=0;v[i];i++)
    {
        int tep=getid(v[i]);
        if(p->next[tep]==NULL)
        {
            p->next[tep]=new trie();
            node[triecont]=p->next[tep];
            p->next[tep]->id=triecont++;
        }
        p=p->next[tep];
    }
    p->mark=1;
}
void getac()
{
    queue<trie*>q;
    q.push(root);
    while(!q.empty())
    {
        trie *p=q.front();
        q.pop();
        for(int i=0;i<4;i++)
        {
            if(p->next[i]==NULL)
            {
                if(p==root) p->next[i]=root;
                else p->next[i]=p->fail->next[i];
            }
            else
            {
                if(p==root) p->next[i]->fail=root;
                else p->next[i]->fail=p->fail->next[i];
                q.push(p->next[i]);
                trie *tep=p;
                while(tep!=root && tep->mark!=1)
                    tep=tep->fail;
                p->mark=tep->mark;
            }
        }
    }
}
int dp[1234][1234];
char fuck[1234];
int main()
{
    int n;
    int cas=1;
    while(scanf("%d",&n),n)
    {
        triecont=0;
        root=new trie();
        node[triecont]=root;
        root->id=triecont++;
        while(n--)
        {
            char x[33];
            scanf("%s",x);
            init(x);
        }
        getac();
        //for(int i=0;i<triecont;i++) printf("%d:%d\n",i,node[i]->mark);
        scanf("%s",fuck+1);
        int len=strlen(fuck+1);
        for(int i=0;i<=len;i++)  for(int j=0;j<triecont;j++) dp[i][j]=inf;
        dp[0][0]=0;
        for(int i=1;i<=len;i++)
        {
            for(int j=0;j<triecont;j++)
            {
                if(dp[i-1][j]==inf) continue;
                for(int k=0;k<4;k++)
                {
                    trie *p=node[j]->next[k];
                    if(p->mark) continue;
                    dp[i][p->id]=min(dp[i][p->id],dp[i-1][j]+(getid(fuck[i])!=k));
                }
            }
        }
        int ans=inf;
        for(int i=0;i<triecont;i++) ans=min(ans,dp[len][i]);
        printf("Case %d: %d\n",cas++,ans==inf?-1:ans);
    }
    return 0;
}
时间: 2024-08-07 00:43:15

[AC自动机+dp] hdu 2457 DNA repair的相关文章

POJ 3691 &amp; HDU 2457 DNA repair (AC自动机,DP)

http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5690   Accepted: 2669 Description Biologists finally invent techniques of repairing DNA that contain

HDU 2457 DNA repair (AC自动机 + DP)

题目链接:DNA repair 解析:给出n个致病DNA序列,给一段DNA片段,问最少修改多少个碱基才能修复这段DNA序列中的所有致病序列. AC自动机 + DP. 将n个致病DNA序列构成一个自动机. 令DP[i][j]表示长度为i走到节点j是所需改变的最少个数. 状态转移时,枚举下一步所有可能的碱基,然后判断该碱基是否达到匹配状态,若能,则安全转移,继续枚举下一个碱基:否则在不匹配的前提下,看该碱基加入之后是否跟上一状态相同,若不同,则需修复,即计数加一.若相同,直接转移即可.然后选择其中最

POJ 3691 &amp;amp; HDU 2457 DNA repair (AC自己主动机,DP)

http://poj.org/problem?id=3691 http://acm.hdu.edu.cn/showproblem.php?pid=2457 DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5690   Accepted: 2669 Description Biologists finally invent techniques of repairing DNA that contain

HDU 2457 DNA repair AC自动机 + dp

http://acm.hdu.edu.cn/showproblem.php?pid=2457 首先把病毒串保存一下,然后对于每一个trie上的节点,跑一发AC自动机,建立一个trie图. 建立的时候,对应做一些修改. 比如,现在建立成了这个样子. 如果he是一个病毒串,那么应该相对应的,把she那个he的位置,标志上,它也是病毒串,也就是不能转移到这一个状态. 这个可以在buildfail的时候对应修改. dp, 设dp[i][j],表示处理到字符串的第i个,走到了AC自动机的第j个节点,变成了

HDU - 2457 DNA repair

Description Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is represented as a string containing characters 'A', 'G' , 'C' and 'T'. The repairing tec

HDU 2457 DNA repair(AC自动机 + DP)题解

题意:n个病毒串,给你一个串t,问你最少改几个能没有病毒串 思路:去年还觉得挺难得...其实就是AC自动机上跑一下简单的DP,每个位置都往没病毒的地方跑,然后看一下最少是什么. 代码: #include<set> #include<map> #include<queue> #include<cmath> #include<string> #include<cstdio> #include<vector> #include&

hdu 2457 AC自动机+dp

DNA repair Time Limit: 5000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 2004    Accepted Submission(s): 1085 Problem Description Biologists finally invent techniques of repairing DNA that contains segments c

HDU2457 DNA repair(AC自动机+DP)

题目一串DNA最少需要修改几个基因使其不包含一些致病DNA片段. 这道题应该是AC自动机+DP的入门题了,有POJ2778基础不难写出来. dp[i][j]表示原DNA前i位(在AC自动机上转移i步)且后缀状态为AC自动机结点j的最少需要修改的基因数 转移我为人人型,从dp[i][j]向ATCG四个方向转移到dp[i+1][j'],如果结点被标记包含致病基因就不能转移. 1 #include<cstdio> 2 #include<cstring> 3 #include<que

Hdu 3341 Lost&#39;s revenge (ac自动机+dp+hash)

题目大意: 给出很多个DNA串,每一个串的价值为1,最后给出一个长串,要你重新排列最后的串使之它所有的子串的权值和最大. 思路分析: 最先容易想到的思路就是搜!管她3721..直接一个字符一个字符的码,然后在AC自动机上判断最后的权值.TLE哟. 然后发现搜过不去,那就dp咯.再容易想到的就是dp[i][a][b][c][d] 表示此时遍历AC自动机的节点在i,然后构成了a个A,b个G,c个C,d个T的权值. 再一看内存,500*40*40*40*40...然后...就没有然后了 再想,因为它说