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 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 are simply to change some characters to eliminate all segments causing diseases. For example, we can repair a DNA "AAGCAG" to "AGGCAC" to eliminate the initial causing disease segments "AAG", "AGC" and "CAG" by changing two characters. Note that the repaired DNA can still contain only characters ‘A‘, ‘G‘, ‘C‘ and ‘T‘.

You are to help the biologists to repair a DNA by changing least number of characters.

Input

The input consists of multiple test cases. Each test case starts with a line containing one integers N (1 ≤ N ≤ 50), which is the number of DNA segments causing inherited diseases.
The following N lines gives N non-empty strings of length not greater than 20 containing only characters in "AGCT", which are the DNA segments causing inherited disease.
The last line of the test case is a non-empty string of length not greater than 1000 containing only characters in "AGCT", which is the DNA to be repaired.

The last test case is followed by a line containing one zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the
number of characters which need to be changed. If it‘s impossible to repair the given DNA, print -1.

Sample Input

2

AAA
AAG

AAAG

2
A
TG

TGAATG

4

A
G
C
T

AGT

0

Sample Output

Case 1: 1

Case 2: 4

Case 3: -1

/*
hdu 2457 AC自动机+dp

给你n个子串和一个主串. 对主串最少修改多少次后使其不包含子串
通过AC自动机能够处理出 一个状态转移图
用dp[i][j]表示长度为i,当前位置为j的最小修改数. nex[j][k] 状态k的节点编号
如果当前位置与主串相同则不需要修改, 否则 +1
而且通过ed数组我们判断当前是否已经走到任意子串的结尾.
那么 dp[i][nex[j][k]] = min(dp[i][nex[j][k]],dp[i-1][j] + (k == str[i]? 0:i));

hhh-2016-04-24 11:23:59
*/
#include <iostream>
#include <vector>
#include <cstring>
#include <string>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <functional>
#include <map>
using namespace std;
#define lson  (i<<1)
#define rson  ((i<<1)|1)
typedef unsigned long long ll;
typedef unsigned int ul;
const int INF = 0x3f3f3f3f;
int tot;
int dp[2][1010];

//struct Matrix
//{
//    int len;
//    int ma[1010][1010];
//    Matrix() {}
//    Matrix(int L)
//    {
//        len = L;
//    }
//};

struct Tire
{
    int nex[1010][4],fail[1010],ed[1010];
    int root,L;
    int newnode()
    {
        for(int i = 0; i < 4; i++)
            nex[L][i] = -1;
        ed[L++] = 0;
        return L-1;
    }

    void ini()
    {
        L = 0,root = newnode();
    }

    int cal(char ch)
    {
        if(ch == ‘A‘)
            return 0;
        else if(ch == ‘C‘)
            return 1;
        else if(ch == ‘G‘)
            return 2;
        else if(ch == ‘T‘)
            return 3;
    }

    void inser(char buf[])
    {
        int len = strlen(buf);
        int now = root;
        for(int i = 0; i < len; i++)
        {
            int ta = cal(buf[i]);
            if(nex[now][ta] == -1)
                nex[now][ta] = newnode();
            now = nex[now][ta];
        }
        ed[now]  ++;
    }

    void build()
    {
        queue<int >q;
        fail[root] = root;
        for(int i = 0; i < 4; i++)
            if(nex[root][i] == -1)
                nex[root][i] = root;
            else
            {
                fail[nex[root][i]] = root;
                q.push(nex[root][i]);
            }
        while(!q.empty())
        {
            int now = q.front();
            q.pop();
            if(ed[fail[now]])
                ed[now] = 1;
            for(int i = 0; i < 4; i++)
            {
                if(nex[now][i] == -1)
                    nex[now][i] = nex[fail[now]][i];
                else
                {
                    fail[nex[now][i]] = nex[fail[now]][i];
                    q.push(nex[now][i]);
                }
            }
        }
    }

//    Matrix to_mat()
//    {
//        Matrix mat(L);
//        memset(mat.ma,0,sizeof(mat.ma));
//        for(int i = 0; i < L; i++)
//        {
//            for(int j = 0; j < 4; j++)
//            {
//                if(!ed[nex[i][j]])
//                    mat.ma[i][nex[i][j]] ++;
//            }
//        }
//        return mat;
//    }
};

//Matrix mat;
Tire ac;
char str[1100];
char buf[22];
int main()
{
    int n;
    int cas = 1;
    while(scanf("%d",&n) != EOF && n)
    {
        ac.ini();
        for(int i = 1; i <= n; i++)
        {
            scanf("%s",buf);
            ac.inser(buf);
        }
        ac.build();
//        mat = ac.to_mat();
        for(int i = 0; i < ac.L; i++)
            dp[0][i] = INF;
        dp[0][0] = 0;
        int cur = 0;
        scanf("%s",str);
        for(int i = 0; i < (int)strlen(str); i++)
        {
            cur ^= 1;
            for(int i = 0; i < ac.L; i++)
                dp[cur][i] = INF;
            for(int j = 0; j < ac.L; j++)
            {
                for(int k = 0; k < 4; k++)
                {
                    if(dp[cur^1][j] != INF && !ac.ed[ac.nex[j][k]])
                        dp[cur][ac.nex[j][k]] = min(dp[cur][ac.nex[j][k]] , dp[cur^1][j] + (k == ac.cal(str[i]) ? 0:1));
                }
            }

        }
        int ans = INF;
        for(int i = 0; i < ac.L; i++)
                ans = min(ans,dp[cur][i]);
        printf("Case %d: ",cas++);
        if(ans == INF)
            cout << -1 <<"\n";
        else
            cout << ans <<"\n";
    }
    return 0;
}

  

时间: 2024-12-26 08:10:50

hdu 2457 AC自动机+dp的相关文章

DNA repair HDU - 2457 AC自动机+DP

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

hdu 2296 aC自动机+dp(得到价值最大的字符串)

Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 3180    Accepted Submission(s): 1033 Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a rom

Lost&#39;s revenge HDU - 3341 AC自动机+DP(需要学会如何优雅的压缩状态)

题意: 给你n个子串和一个母串,让你重排母串最多能得到多少个子串出现在重排后的母串中. 首先第一步肯定是获取母串中每个字母出现的次数,只有A T C G四种. 这个很容易想到一个dp状态dp[i][A][B][C][D] 表示在AC自动机 i 这个节点上,用了A个A,B个T,C个C,D个G. 然后我算了一下内存,根本开不下这么大的内存. 看了网上题解,然后用通过状压把,A,B,C,D压缩成一维. 这个状压就是通过进制实现需要实现唯一表示 bit[0] = 1; bit[1] = (num[0]

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

题目大意:给你N个DNA的串,也就是至包含'A','T','G','C'四种碱基的,这些给定的串都是带有遗传病的,然后给你一个不会超过1000的串,问你至少几个地方才能让这个串不包含遗传病,如果不论怎么修改都没用,输出'-1'   分析:用dp[Ni][nNode],表示长度为i时候到达第n个节点修改的最小次数,然后统计最后一层次最小次数就行了.   代码如下: ===================================================================

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

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

hdu 2825 aC自动机+状压dp

Wireless Password Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 5640    Accepted Submission(s): 1785 Problem Description Liyuan lives in a old apartment. One day, he suddenly found that there

HDU 3341 Lost&#39;s revenge AC自动机+dp

Lost's revenge Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others)Total Submission(s): 3757    Accepted Submission(s): 1020 Problem Description Lost and AekdyCoin are friends. They always play "number game"(A bor

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...然后...就没有然后了 再想,因为它说

HDU 4518 ac自动机+数位dp

吉哥系列故事--最终数 Time Limit: 500/200 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) Total Submission(s): 304    Accepted Submission(s): 102 Problem Description 在2012年腾讯编程马拉松比赛中,吉哥解决了一道关于斐波那契的题目,这让他非常高兴,也更加燃起了它对数学特别是斐波那契数的热爱.现在,它又在思考一个关于斐波那契