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