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

来源:互联网 发布:打车 数据 编辑:程序博客网 时间:2024/06/05 19:12

题目链接:DNA repair


解析:给出n个致病DNA序列,给一段DNA片段,问最少修改多少个碱基才能修复这段DNA序列中的所有致病序列。

AC自动机 + DP。

将n个致病DNA序列构成一个自动机。

令DP[i][j]表示长度为i走到节点j是所需改变的最少个数。

状态转移时,枚举下一步所有可能的碱基,然后判断该碱基是否达到匹配状态,若能,则安全转移,继续枚举下一个碱基;否则在不匹配的前提下,看该碱基加入之后是否跟上一状态相同,若不同,则需修复,即计数加一。若相同,直接转移即可。然后选择其中最小的修复个数即可。



AC代码:

#include <iostream>#include <cstdio>#include <queue>#include <cstring>using namespace std;const int INF = 0x3f3f3f3f;struct Trie{    int next[1010][4], fail[1010];    bool 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 getch(char ch){        if(ch == 'A') return 0;        if(ch == 'C') return 1;        if(ch == 'G') return 2;        else return 3;    }    void insert(char s[]){        int len = strlen(s);        int now = root;        for(int i = 0; i < len; i++){            if(next[now][getch(s[i])] == -1)                next[now][getch(s[i])] = newnode();            now = next[now][getch(s[i])];        }        end[now] = true;    }    void build(){        queue<int> Q;        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] ] == true) end[now] = true;    //注意            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 newj = next[j][k];                        if(end[newj]) continue;       //可以安全转移                        int tmp;                        if(k == getch(buf[i])) tmp = dp[i][j];    //相同,无需修复                        else tmp = dp[i][j] + 1;    //不同,修复次数加一                        dp[i+1][newj] = min(dp[i+1][newj], tmp);                    }                }        int ans = INF;        for(int i=0; i<L; i++)            ans = min(ans, dp[len][i]);    //选择最小的修复次数        if(ans == INF) ans = -1;        return ans;    }};Trie ac;char buf[1010];int main(){    #ifdef sxk        freopen("in.txt", "r", stdin);    #endif //sxk    int n;    int kase = 0;    while(scanf("%d", &n) == 1 && n){        ac.init();        for(int i = 0; i < n; i ++){            scanf("%s", buf);            ac.insert(buf);        }        ac.build();        scanf("%s", buf);        printf("Case %d: %d\n", ++kase, ac.solve(buf));    }    return 0;}



0 0
原创粉丝点击