您的位置:首页 > 其它

[AC自动机+dp+变进制状压] hdu 3341 Lost's revenge

2014-10-31 10:17 501 查看
题意思路摘自大神:http://www.cppblog.com/menjitianya/archive/2014/07/11/207604.html#207622

题意:给定N(N <= 50)个长度不超过10的模式串(ACGT串),再给定一个长度为M(M <= 40)的目标串S,求将目标串重排列,使得它包含最多的模式串,求这个最多的数目。

题解:利用模式串建立trie图,trie图上最多有500个结点( N*10 ),然后朴素的思想就是用S(i, iA, iC, iG, iT)表示在i状态下,拥有iA个A、iC个C、iG个G、iT个T的串拥有的最多的模式串的个数,但是iA, iC, iG, iT的取值均是[0,
40],所以我们需要把状态压缩一下,我们知道当四种字符都取10的时候可以让状态数达到最大,即114 = 14641, 所以可以令MaxA、

MaxC、MaxG、MaxT分别表示四种字符出现的个数,那么T字符的权值为1,G字符的权值为(MaxT + 1),C字符的权值为(MaxG + 1) *(MaxT + 1),A字符的权值为(MaxC + 1) *(MaxG + 1) *(MaxT + 1),进行进制压缩之后总的状态数不会超过114,可以用DP[i][j]表示在trie的i号结点时ACGT四个字符个数的压缩状态为j时的字符串包含模式串的最多数目,然后就是进行O(4*500*114)的状态转移了。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"map"
#include"iostream"
using namespace std;
int triecont;
char fuck[55];
struct trie
{
    int mark,id;
    trie *next[6],*fail;
    trie()
    {
        mark=id=0;
        memset(next,0,sizeof(next));
        fail=NULL;
    }
};
trie *root,*node[520];
int getid(char x)
{
    if(x=='A') return 0;
    if(x=='C') return 1;
    if(x=='G') return 2;
    return 3;
}
void init(char *v)
{
    trie *p=root;
    for(int i=0; v[i]; i++)
    {
        int tep=getid(v[i]);
        if(p->next[tep]==NULL)
        {
            p->next[tep]=new trie();
            node[triecont]=p->next[tep];
            p->next[tep]->id=triecont++;
        }
        p=p->next[tep];
    }
    p->mark++;
}
void getac()
{
    queue<trie*>q;
    q.push(root);
    while(!q.empty())
    {
        trie *p=q.front();
        q.pop();
        for(int i=0; i<4; i++)
        {
            if(p->next[i]==NULL)
            {
                if(p==root) p->next[i]=root;
                else p->next[i]=p->fail->next[i];
            }
            else
            {
                if(p==root) p->next[i]->fail=root;
                else p->next[i]->fail=p->fail->next[i];
                q.push(p->next[i]);
                if(p!=root) p->next[i]->mark+=p->next[i]->fail->mark;
            }
        }
    }
}
int dp[520][15000];
int main()
{
    int n,cas=1;
    while(scanf("%d",&n),n)
    {
        memset(node,0,sizeof(node));
        triecont=0;
        root=new trie();
        node[triecont]=root;
        root->id=triecont++;

        while(n--)
        {
            char x[123];
            scanf("%s",x);
            init(x);
        }
        getac();
        scanf("%s",fuck);
        int used[12],bit[12];
        memset(used,0,sizeof(used));
        memset(bit,0,sizeof(bit));
        for(int i=0; fuck[i]; i++)
        {
            used[getid(fuck[i])]++;
        }
        bit[0]=(used[3]+1)*(used[2]+1)*(used[1]+1);
        bit[1]=(used[3]+1)*(used[2]+1);
        bit[2]=(used[3]+1);
        bit[3]=1;
        memset(dp,-1,sizeof(dp));
        dp[0][0]=0;
        for(int A=0; A<=used[0]; A++)
        {
            for(int B=0; B<=used[1]; B++)
            {
                for(int C=0; C<=used[2]; C++)
                {
                    for(int D=0; D<=used[3]; D++)
                    {
                        int tep=A*bit[0]+B*bit[1]+C*bit[2]+D*bit[3];
                        for(int j=0; j<triecont; j++)
                        {
                            if(dp[j][tep]!=-1)
                            {
                                for(int k=0;k<4;k++)
                                {
                                    if(k==0 && used[0]==A) continue;
                                    if(k==1 && used[1]==B) continue;
                                    if(k==2 && used[2]==C) continue;
                                    if(k==3 && used[3]==D) continue;
                                    trie *p=node[j]->next[k];
                                    dp[p->id][tep+bit[k]]=max(dp[p->id][tep+bit[k]],dp[j][tep]+p->mark);
                                }
                            }
                        }
                    }
                }
            }
        }
        int ans=0;
        int lit=used[0]*bit[0]+used[1]*bit[1]+used[2]*bit[2]+used[3]*bit[3];
        for(int i=0;i<triecont;i++) ans=max(ans,dp[i][lit]);
        printf("Case %d: %d\n",cas++,ans);
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: