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

题意:

给出目标串,给出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;
}
/**

*/




你可能感兴趣的:(hdu 3341 Lost's revenge (ac自动机+状压dp))