poj 3691

 

ac自动机+dp 自动机上的节点来作为状态

dp[i][j]表示长度为i状态为j至少需要转换多少个字符

#include <iostream>

#include <cstdio>

#include <cstring>

#include <queue>

using namespace std;

const int root=0,N=4;

char a[1111];

int dp[1111][1111],c[1111][10];

struct

{

    int next[5],tmp,fail;

}trie[1111];

int lon;

void trieini()

{

    memset(trie,0,sizeof(trie));

    lon=0;

}



void insert(char s[])

{

    int t=root;

    int n=strlen(s+1);

    for(int i=1;i<=n;i++)

    {

        if(trie[t].next[s[i]-'A']==0)

        trie[t].next[s[i]-'A']=++lon;

        t=trie[t].next[s[i]-'A'];

        if(i==n)

        trie[t].tmp++;

    }

}



void getfail()

{

    queue <int> q;

    q.push(root);

    while(!q.empty())

    {

        int t=q.front();

        q.pop();

        for(int i=0;i<N;i++)

        if(trie[t].next[i])

        {

            int u=trie[t].next[i];

            int tmp=trie[t].fail;

            while(tmp!=root&&trie[tmp].next[i]==0)

            tmp=trie[tmp].fail;

            trie[u].fail=trie[tmp].next[i];

            if(t==root) trie[u].fail=root;

            trie[u].tmp+=trie[trie[u].fail].tmp;

            q.push(u);

        }

    }

}



void find()

{

    for(int i=0;i<=lon;i++)

    {

        for(int k=0;k<N;k++)

        {

            int t=i;

            while(t&&trie[t].next[k]==0) t=trie[t].fail;

            if(trie[t].next[k])

            c[i][k]=trie[t].next[k];

            else

            c[i][k]=root;

        }

    }

}



void work(char a[])

{

    int n=strlen(a+1);

    for(int i=1;i<=n;i++)

    {

        if(a[i]=='T')

        a[i]='B';

        else if(a[i]=='G')

        a[i]='D';

    }

}



int main()

{

    int n;

    int tcase=0;

    while(scanf("%d",&n),n)

    {

        trieini();

        for(int i=1;i<=n;i++)

        {

            char s[22];

            scanf("%s",s+1);

            work(s);

            insert(s);

        }

        getfail();

        find();

        scanf("%s",a+1);

        work(a);

        memset(dp,50,sizeof(dp));

        dp[0][0]=0;

        int m=strlen(a+1);

        for(int k=0;k<m;k++)

        for(int i=0;i<=lon;i++)

        if(trie[i].tmp==0)

        {

            for(int p=0;p<N;p++)

            {

                int tmp=p+'A'!=a[k+1];

                dp[k+1][c[i][p]]=min(dp[k+1][c[i][p]],dp[k][i]+tmp);

            }

        }

        int ans=1111;



        for(int i=0;i<=lon;i++)

        if(trie[i].tmp==0)

        {

            ans=min(ans,dp[m][i]);

//            printf("%d %d %d\n",m,i,dp[m][i]);

        }



        printf("Case %d: ",++tcase);

        if(ans==1111)

        printf("-1\n");

        else

        printf("%d\n",ans);

    }

    return 0;

}



你可能感兴趣的:(poj)