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
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 

题意: 给出一些不合法的模式DNA串,给出一个原串,问最少需要修改多少个字符,使得原串中不包含非法串
思路:首先我们构造一个AC自动机,然后为了保证不匹配到子串所以我们规定不走到每个子串的尾,然后就是在除了不能走的位置的DP,设dp[i][j]表示母串走到第i个单词,自动机匹配到j的状态的最小值,在保证了不会匹配的前提下,那么遇到一个不相同的字母的时候,我们需要修改子串使得与母串相同,相同的话就不改了,我们现在是尽量往母串改。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int inf = 0x3f3f3f3f;

struct Trie {
    int next[1010][4], fail[1010];
    int end[1010];
    int root, L;

    int newNode() {
        for (int i = 0; i < 4; i++)
            next[L][i] = -1;
        end[L++] = false;
        return L-1;
    }

    void init() {
        L = 0;
        root = newNode();
    }

    int getInt(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 insert(char buf[]) {
        int len = strlen(buf);
        int now = root;
        for (int i = 0; i < len; i++) {
            if (next[now][getInt(buf[i])] == -1)
                next[now][getInt(buf[i])] = newNode();
            now = next[now][getInt(buf[i])];
        }
        end[now] = 1;
    }

    void build() {
        queue<int> Q;
        fail[root] = root;
        for (int i = 0; i < 4; i++) {
            if (next[root][i] == -1)
                next[root][i] = root;
            else {
                fail[next[root][i]] = root;
                Q.push(next[root][i]);
            }
        }

        while (!Q.empty()) {
            int now = Q.front();
            Q.pop();
            if (end[fail[now]]) end[now] = 1; //notice
            for (int i = 0; i < 4; 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]);
                }
        }
    }
    int dp[1010][1010];
    int solve(char buf[]) {
        int len = strlen(buf);
        for (int i = 0; i <= len; i++)
            for (int j = 0; j < L; j++)
                dp[i][j] = inf;

        dp[0][root] = 0;
        for (int i = 0; i < len; i++)
            for (int j = 0; j < L; j++)
                if (dp[i][j] != inf) {
                    for (int k = 0; k < 4; k++) {
                        int news = next[j][k];
                        if (end[news]) continue;
                        int tmp;
                        if (k == getInt(buf[i]))
                            tmp = dp[i][j];
                        else tmp = dp[i][j] + 1;
                        dp[i+1][news] = min(dp[i+1][news], tmp);
                    }
                }

        int ans = inf;
        for (int j = 0; j < L; j++)
            ans = min(ans, dp[len][j]);
        if (ans == inf)
            ans = -1;
        return ans;
    }
} ac;
char buf[1010];

int main() {
    int n, cas = 1;
    while (scanf("%d", &n) != EOF && n) {
        ac.init();
        while (n--) {
            scanf("%s", buf);
            ac.insert(buf);
        }

        ac.build();
        scanf("%s", buf);
        printf("Case %d: %d\n", cas++, ac.solve(buf));
    }
    return 0;
}
时间: 2024-10-11 07:45:50

HDU - 2457 DNA repair的相关文章

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

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是所需改变的最少个数. 状态转移时,枚举下一步所有可能的碱基,然后判断该碱基是否达到匹配状态,若能,则安全转移,继续枚举下一个碱基:否则在不匹配的前提下,看该碱基加入之后是否跟上一状态相同,若不同,则需修复,即计数加一.若相同,直接转移即可.然后选择其中最

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个节点,变成了

[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,

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

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

HDU 1560 DNA sequence(DNA序列)

p.MsoNormal { margin: 0pt; margin-bottom: .0001pt; text-align: justify; font-family: Calibri; font-size: 10.5000pt } h1 { margin-top: 5.0000pt; margin-bottom: 5.0000pt; text-align: center; font-family: 宋体; color: rgb(26,92,200); font-weight: bold; fo