HDU 2457 DNA repair AC自動機+DP

http://acm.hdu.edu.cn/showproblem.php?pid=2457

題意: 給出了一些病毒串的基因, 又給出了一個基因串,問至少修改多少個基因串中的字符可以不含病毒串。


首先把病毒建立一個自動機。

dp[i][j]表示 長度爲i的字符串以狀態j結尾時,最少修改數

dp[0][0]=0,其他無窮


那麼dp[i][j]可以用 dp[i-1][k]也就是長度爲i-1時,狀態爲k的節點轉移過來,

轉移的條件是,k本身不是病毒節點,且k的後繼節點j也不是病毒節點


最後掃描dp[n][i],如果爲inf表示無法轉到此狀態

取min值即是答案


dp爲1000*1000

#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;

const int maxlen=1000+50;
const int maxn=1005;
const int all_size=4;
int trie[maxn][all_size];
int fail[maxn];
int tag[maxn];

int sz;
queue<int >Q;
int n;
struct Aho
{
    int root;
    int newnode()//靜態創建新節點
    {
        memset(trie[sz],-1,sizeof trie[sz]);
        tag[sz]=0;
        sz++;
        return sz-1;
    }
    void init()//初始化
    {
        sz=0;
        newnode();
    }
    void insert(char s[],int id)   //插入字符串構建ac自動機,構建trie樹
    {
        int len=strlen(s),p=0;;
        for (int i=0; i<len; i++)
        {
            int id=s[i]-'0';
            if (trie[p][id]==-1)
                trie[p][id]=newnode();
            p=trie[p][id];
        }
        tag[p]=id;   //結束標記
    }
    void getfail() //構建自動機fail指針
    {
        while(!Q.empty()) Q.pop();
        fail[root]=root;            //root指向root
        for (int i=0; i<all_size; i++)
        {
            if (trie[root][i]==-1)//第一個字符不存在,指向root
                trie[root][i]=root;
            else    //第一個字符的fail指針指向root
            {
                fail[trie[root][i]]=root;
                Q.push(trie[root][i]);   //並放入隊列,待bfs擴展
            }
        }
        while(!Q.empty())
        {
            int u=Q.front();    //取擴展節點
            Q.pop();
            if(tag[fail[u]])     tag[u]=1;  //***如果之前是tag,直接標記
            for (int i=0; i<all_size; i++)//遍歷所有子節點
            {
                if (trie[u][i]==-1)//如果不存在,則子節點直接指向fail[u]節點的對應子節點
                    trie[u][i]=trie[fail[u]][i];
                else     //如果存在,則該節點的fail指針指向fail[u]節點對應的子節點
                {
                    fail[trie[u][i]]=trie[fail[u]][i];
                    Q.push(trie[u][i]);     //繼續擴展
                }
            }
        }
    }

} aho;
char ss[maxlen];
char cop[maxlen];
char name[55][25];
void change(char *ss)
{
    int len=strlen(ss);
    for (int i=0; i<len; i++)
        if (ss[i]=='A') ss[i]='0'+0;
        else     if (ss[i]=='T')ss[i]='0'+1;
        else     if (ss[i]=='C')ss[i]='0'+2;
        else     if (ss[i]=='G')ss[i]='0'+3;
}
int dp[1005][1005];
const int inf=1e6;
int main()
{

    int cnt=1;
    while(cin>>n&&n)
    {
        aho.init();
        for (int i=0; i<n; i++)
        {
            scanf("%s",name[i]);
            int len=strlen(name[i]);
            change(name[i]);
            aho.insert(name[i],i+1);
        }

        aho.getfail();

        scanf("%s",ss);
        change(ss);
        int len=strlen(ss);

        for (int i=0; i<=len; i++)
            for (int j=0; j<sz; j++)
                dp[i][j]=inf;


        dp[0][0]=0;
        for (int L=1; L<=len; L++)
        {
            for (int i=0; i<sz; i++)
            {
                if (tag[i])continue;
                if (dp[L-1][i]==inf) continue;
                int id=ss[L-1]-'0';
                for (int j=0; j<all_size; j++)
                {
                    if (tag[trie[i][j]])continue;
                    int add=(j!=id);
                    dp[L][trie[i][j]]=min(dp[L][trie[i][j]],
                                          dp[L-1][i]+add);
                }
                int cc;
            }
        }
        int ans=inf;
        for (int i=0; i<sz; i++)
            ans=min(ans,dp[len][i]);


        printf("Case %d: ",cnt++);
        if (ans==inf)
            printf("-1\n");
        else
            printf("%d\n",ans);


    }
    return 0;
}
















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章