链接:点击打开链接
题意:给出n段基因的价值和组成,求一个长度为l的价值大于零最大的基因价值
代码:
#include <queue> #include <stdio.h> #include <string.h> #include <stdlib.h> #include <iostream> #include <algorithm> using namespace std; const int INF=0x3f3f3f3f; int q[1005],dp[2][1005][(1<<10)+5]; int fail[100005],vis[100005],val[100005]; int str[100005][30],dis[100005]; int root,id; int change(char c){ if(c=='A')return 0; if(c=='T')return 1; if(c=='G')return 2; if(c=='C')return 3; return 0; } //只有四个字母 void insert(char *s){ int u=0; for(;*s;s++){ if(!str[u][change(*s)]) str[u][change(*s)]=root++; u=str[u][change(*s)]; } dis[u]|=(1<<(id-1)); id++; } void getfail(){ int u,v,i,l,r,temp; l=0,r=0; q[r++]=0; while(l<r){ u=q[l++]; for(i=0;i<4;i++){ if(!str[u][i]) str[u][i]=str[fail[u]][i]; else { temp=str[u][i]; if(u) fail[temp]=str[fail[u]][i]; dis[temp]|=dis[fail[temp]]; q[r++]=temp; } } } } //自动机模板 int cal(int t,int m){ int i,ans; ans=0; for(i=0;i<m;i++) if(t&(1<<i)) ans+=val[i]; return ans; } //计算出每个状态的价值 int main(){ int n,m,k,i,j,x,y,z,ans; char s[1005]; while(scanf("%d%d",&m,&k)!=EOF){ root=id=1; memset(str,0,sizeof(str)); memset(val,0,sizeof(val)); memset(dis,0,sizeof(dis)); memset(fail,0,sizeof(fail)); for(i=0;i<m;i++){ scanf("%s%d",s,&val[i]); insert(s); } getfail(); memset(dp,0,sizeof(dp)); dp[0][0][0]=1; for(x=0;x<k;x++){ //空间不够,因此用滚动数组 memset(dp[(x+1)&1],0,sizeof(dp[(x+1)&1])); for(y=0;y<root;y++) for(z=0;z<(1<<m);z++) if(dp[x&1][y][z]) for(j=0;j<4;j++){ dp[(x+1)&1][str[y][j]][z|dis[str[y][j]]]=dp[x&1][y][z]; } } //自动机+状态压缩dp的题还是很相似的 ans=-INF; for(i=0;i<(1<<m);i++) for(j=0;j<root;j++) if(dp[k&1][j][i]) ans=max(ans,cal(i,m)); if(ans<0) puts("No Rabbit after 2012!"); else printf("%d\n",ans); } return 0; }