hdu 3341 Lost's revenge (ac自动机+状压dp)

来源:互联网 发布:zhipan.cn 域名城 编辑:程序博客网 时间:2024/05/22 03:50

题意:

给出目标串,给出n个模式串,现在问如何排列目标串使得目标串能含最多的模式串(可以重叠)。

题解:

好题!

这题用状压,很明显只能用状压,一开想的也是状压但是没想到这样去状压。我们枚举串出现AGCT的个数,然后得到状态转移。代码犯了几个脑残的错误,word[now]++,word[now]+=word[fail[now]];

上次犯用手写队列被卡内存了,甚是无语,看来以后还是用容器。


#include<iostream>#include<math.h>#include<stdio.h>#include<algorithm>#include<string.h>#include<vector>#include<queue>#include<map>#include<set>using namespace std;#define B(x) (1<<(x))typedef long long ll;const int oo=0x3f3f3f3f;const ll OO=1LL<<61;const ll MOD=20090717;const int maxn=50;const int SIZE=505;const int alph=4;char str[maxn];int dp[SIZE][11*11*11*11+5];///其妙的状态压缩int bit[4],num[4];map<char,int>mat;struct AC{    int next[SIZE][alph],fail[SIZE],Word[SIZE];    int root,cnt;    void Init()    {        cnt=0;        root=newNode();    }    int newNode()    {        for(int i=0;i<alph;i++)            next[cnt][i]=-1;        Word[cnt++]=0;        return cnt-1;    }    void Insert(char buff[])    {        int now=root;        int len=strlen(buff);        for(int i=0,k;i<len;i++)        {            k=mat[buff[i]];            if(next[now][k]==-1)                next[now][k]=newNode();            now=next[now][k];        }        Word[now]++;///单词个数,这里犯傻了把word[now]=1;    }    void build()    {        queue<int>Q;        fail[root]=root;        int now=root;        for(int i=0;i<alph;i++)        {            if(next[now][i]==-1)                next[now][i]=root;            else            {                fail[next[now][i]]=root;                Q.push(next[now][i]);            }        }        while(!Q.empty())        {            now=Q.front();            Q.pop();            Word[now]+=Word[fail[now]];///因为是状态压缩类似背包的,所以单词个数是要累加的,说不清楚            for(int i=0;i<alph;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]);                }            }        }    }    void preSolve()    {        memset(dp,-1,sizeof dp);        memset(num,0,sizeof num);        int len=strlen(str);        for(int i=0;i<len;i++)            num[mat[str[i]]]++;        bit[3]=1;        bit[2]=bit[3]*(num[3]+1);        bit[1]=bit[2]*(num[2]+1);        bit[0]=bit[1]*(num[1]+1);    }    int cmax(int& a,int b)    {        if(b>a)            a=b;    }    int DP()    {        preSolve();        dp[0][0]=0;        for(int A=0;A<=num[0];A++)        {            for(int G=0;G<=num[1];G++)            {                for(int C=0;C<=num[2];C++)                {                    for(int T=0;T<=num[3];T++)                    {                        int s=A*bit[0]+G*bit[1]+C*bit[2]+T*bit[3];                        for(int i=0;i<cnt;i++)                        if(dp[i][s]!=-1)                        {                            for(int j=0;j<4;j++)                            {                                int now=next[i][j];                                if(j==0&&A==num[0])continue;                                if(j==1&&G==num[1])continue;                                if(j==2&&C==num[2])continue;                                if(j==3&&T==num[3])continue;                                cmax(dp[now][s+bit[j]],dp[i][s]+Word[now]);                            }                        }                    }                }            }        }        int ans=0;        int full=num[0]*bit[0]+num[1]*bit[1]+num[2]*bit[2]+num[3]*bit[3];        for(int i=0;i<cnt;i++)            cmax(ans,dp[i][full]);        return ans;    }};AC ac;int main(){    int n,cas=1;    mat['A']=0;    mat['G']=1;    mat['C']=2;    mat['T']=3;    while(scanf("%d",&n)!=EOF)    {        if(n==0)break;        ac.Init();        for(int i=1;i<=n;i++)        {            scanf("%s",str);            ac.Insert(str);        }        scanf("%s",str);        ac.build();        printf("Case %d: %d\n",cas++,ac.DP());    }    return 0;}/***/


0 0