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