DNA repair - HDU 2457(自动机+dp)

题目大意:给你N个DNA的串,也就是至包含‘A‘,‘T‘,‘G‘,‘C‘四种碱基的,这些给定的串都是带有遗传病的,然后给你一个不会超过1000的串,问你至少几个地方才能让这个串不包含遗传病,如果不论怎么修改都没用,输出‘-1‘

 

分析:用dp[Ni][nNode],表示长度为i时候到达第n个节点修改的最小次数,然后统计最后一层次最小次数就行了。

 

代码如下:

=============================================================================================================================

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

const int MAXN = 1007;
const int MAXM = 57;
const int MaxSon = 4;
const int oo = 1e9+7;

int dp[MAXN][MAXN];

struct Ac_Trie
{
    int next[MAXN][MaxSon];
    int Fail[MAXN], End[MAXN];
    int cnt, root;

    int newnode()
    {
        for(int i=0; i<MaxSon; i++)
            next[cnt][i] = -1;
        Fail[cnt] = End[cnt] = false;

        return cnt++;
    }
    void InIt()
    {
        cnt = 0;
        root = newnode();
    }
    int Find(char ch)
    {
        if(ch == ‘A‘)return 0;
        if(ch == ‘T‘)return 1;
        if(ch == ‘G‘)return 2;

        return 3;
    }
    void Insert(char s[])
    {
        int now = root;

        for(int i=0; s[i]; i++)
        {
            int k = Find(s[i]);

            if(next[now][k] == -1)
                next[now][k] = newnode();
            now = next[now][k];
        }

        End[now] = true;
    }
    void GetFial()
    {
        queue<int>Q;
        int now = root;

        for(int i=0; i<MaxSon; i++)
        {
            if(next[now][i] == -1)
                next[now][i] = root;
            else
            {
                Fail[next[now][i]] = root;
                Q.push(next[now][i]);
            }
        }

        while(Q.size())
        {
            now = Q.front();
            Q.pop();

            for(int i=0; i<MaxSon; i++)
            {
                if(next[now][i] == -1)
                    next[now][i] = next[Fail[now]][i];
                else
                {
                    Fail[next[now][i]] = next[Fail[now]][i];
                    Q.push(next[now][i]);
                }
            }

            End[now] |= End[Fail[now]];
        }
    }
};
Ac_Trie ac;

int main()
{
    int N, t=1;

    while(scanf("%d", &N), N)
    {
        char s[MAXN];
        ac.InIt();

        for(int i=0; i<N; i++)
        {
            scanf("%s", s);
            ac.Insert(s);
        }
        ac.GetFial();

        scanf("%s", s+1);
        N = strlen(s);

        for(int i=0; i<=N; i++)
        for(int j=0; j<ac.cnt; j++)
            dp[i][j] = oo;

        dp[0][0] = 0;

        for(int i=0; i<N-1; i++)
        for(int j=0; j<ac.cnt; j++)
        for(int k=0; k<4; k++)
        {
            int w = dp[i][j];
            int next = ac.next[j][k];

            if(ac.End[next])continue;

            if(ac.Find(s[i+1]) != k)
                w++;

            if(dp[i+1][next] > w)
                dp[i+1][next] = w;
        }

        int Min = oo;

        for(int i=0; i<ac.cnt; i++)
            Min = min(Min, dp[N-1][i]);

        if(Min == oo)
            Min = -1;

        printf("Case %d: %d\n", t++, Min);
    }

    return 0;
}
时间: 2024-10-10 06:59:57

DNA repair - HDU 2457(自动机+dp)的相关文章

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

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

poj 3691 DNA repair(AC自动机+dp)

DNA repair Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5877   Accepted: 2760 Description Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a

【POJ3691】 DNA repair (AC自动机+DP)

DNA repair Time Limit: 2000MS Memory Limit: 65536KB 64bit IO Format: %I64d & %I64u Description Biologists finally invent techniques of repairing DNA that contains segments causing kinds of inherited diseases. For the sake of simplicity, a DNA is repr

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

DNA repair HDU - 2457 AC自动机+DP

题意: 给你N个模板串,并且给你一个文本串, 现在问你这个文本串最少需要改变几个字符才能使得它不包含任何模板串. (以上字符只由A,T,G,C构成) 题解: 刚开始做这一题的时候表示很懵逼,好像没有学过这种类型的问题. 后面仔细想想,在之前的题目中,学会了求出不包含任何模板串的方案数. 这题可以转化下,求出所有不包含任何模板串的方案中与原串最少的不同数目. 根据这个DP dp[i][j] 表示走到长度为 i 的时候,在AC自动机 j 这个节点上最多与原串不同的个数. 然后这题就变成SB题了. 1

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&

18.10.29 POJ 3691 DNA repair(AC自动机+dp)

描述 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 techniques a

POJ 3691 DNA repair 基于AC自动机的DP

dp[i][j] 表示长度为 i 的前缀到达第 j 个节点的最小更改数目. 很显然有dp[0][0] = 0; dp[ i ][ j ] = min(dp[ i ][ j ],dp[i-1][k] + (j == k ? 0 : 1)),当且仅当j,k满足下列条件时. j 不为某条模式串的末节点 且 j 到 root 的由失败指针组成的路径上无末节点. j 是k的儿子节点 或者 j 的父节点可由 k 沿着失败指针找到. #include <algorithm> #include <ios

Lost&#39;s revenge - HDU 3341 (自动机+DP)

题目大意:先给你一些子串,然后给你一个母串,母串里面的字母可以任意调换位置,问最多这个母串经过一些位置变动最多能包含多少个子串.   分析:可以比较明显的看出来的DP,先求出来ATGC分别有多少,然后再处理,不过有个比较麻烦的地方,因为ATGC的字母数最多是40,因为不知道那种字母所以是40*40*40*40,很明显这种复杂度太高,开始使用了一次打标,把每种状态都保存下来,并且保存它的下一个状态,不过很不幸这种方法TLE了,因为找他的下一个状态不是太容易,看了大神的题解后明白,其实可以使用4种不