HDU 3341Lost's revenge

来源:互联网 发布:软件安装管理器2015 编辑:程序博客网 时间:2024/06/09 19:09

给定n个模式串和一个目标串,求将目标串重排列后所能包含的最多的模式串个数。可以开个dp[s][a][c][g][t]来记录状态转移,s为结点状态,但是a,c,g,t的值范围为[0,40],很明显数组爆了,于是有个很神奇的方法,可以利用状态压缩把状态压成最多11*11*11*11的大小来标记a,c,g,t. num[4]来记录a,c,g,t出现的次数。bits[4]代表对应的权值,那么bits[0]=(num[1]+1)*(num[2]+1)*(num[3]+1),bits[1]=(num[2]+1)*(num[3]+1),bits[2]=(num[3]+1),bits[3]=1; 假设枚举a,b,c,d时对应的下标为A,B,C,D。那么此时对应的状态status=num[A]*bits[A]+num[B]*bits[B]+num[C]*bits[C]+num[D]*bits[D].那么只需要dp[s][11<<4]来记行dp就可以了,最终的答案为最大的

dp[i][status],i为所有结点,status=num[0]*bits[0]+num[1]*bits[1]+num[2]*bits[2]+num[3]*bits[3].我觉得应该是a,b,c,d对应在定义好的一段上吧?我也不是十分理解...代码如下

#include<stdio.h>#include<iostream>#include<string.h>#include<algorithm>#include<queue>using namespace std;const int INF=1e9;const int MOD=20090717;struct Tree{int next[510][26],end[510],fail[510];int L,root;int newnode(){for(int i=0;i<26;i++){next[L][i]=-1;}end[L++]=0;return L-1;}void init(){L=0;root=newnode();}int getch(char ch){if(ch=='A') return 0;else if(ch=='G') return 1;else if(ch=='C') return 2;else if(ch=='T') return 3;}void insert(char *s){int len=strlen(s);int p=root;for(int i=0;i<len;i++){int id=getch(s[i]);if(next[p][id]==-1){next[p][id]=newnode();}p=next[p][id];}end[p]++;}void build(){queue<int>q;int p=root;fail[root]=root;for(int i=0;i<26;i++){//printf("%d %d %d\n",i,p,next[p][i]);if(next[p][i]==-1){next[p][i]=root;}else{fail[next[p][i]]=root;q.push(next[p][i]);}}while(!q.empty()){p=q.front();q.pop();if(end[fail[p]]) end[p]+=end[fail[p]];  for(int i=0;i<26;i++){if(next[p][i]==-1){next[p][i]=next[fail[p]][i];}else{fail[next[p][i]]=next[fail[p]][i];q.push(next[p][i]);}}}}int dp[510][11*11*11*11+2];int num[4],bit[4];void solve(char *s){int len=strlen(s);memset(num,0,sizeof(num));for(int i=0;i<len;i++){num[getch(s[i])]++;}bit[0]=(num[1]+1)*(num[2]+1)*(num[3]+1);bit[1]=(num[2]+1)*(num[3]+1);bit[2]=(num[3]+1);bit[3]=1;memset(dp,-1,sizeof(dp));dp[0][0]=0;for(int A=0;A<=num[0];A++){for(int B=0;B<=num[1];B++){for(int C=0;C<=num[2];C++){for(int D=0;D<=num[3];D++){int s=A*bit[0]+B*bit[1]+C*bit[2]+D*bit[3];for(int i=0;i<L;i++){if(dp[i][s]>=0)for(int k=0;k<4;k++){if(k==0&&A==num[0]) continue;if(k==1&&B==num[1]) continue;if(k==2&&C==num[2]) continue;if(k==3&&D==num[3]) continue;dp[next[i][k]][s+bit[k]]=max(dp[next[i][k]][s+bit[k]],dp[i][s]+end[next[i][k]]);}}}}}}int status=num[0]*bit[0]+num[1]*bit[1]+num[2]*bit[2]+num[3]*bit[3];int ans=0;for(int i=0;i<L;i++){ans=max(ans,dp[i][status]);}printf("%d\n",ans);}/*void query(char *s){int len=strlen(s);int p=root,ans=0;memset(cnt,0,sizeof(cnt));memset(last,-1,sizeof(last));for(int i=0;i<len;i++){int id=s[i]-'a';p=next[p][id];int temp=p;while(temp!=root){cnt[0][temp]++;if(i-last[temp]>=deep[temp]){cnt[1][temp]++;last[temp]=i;}temp=fail[temp];}}}*//*void debug()    {        for(int i = 0;i < L;i++)        {            printf("id = %3d,fail = %3d,end = %3d,chi = [",i,fail[i],end[i]);            for(int j = 0;j < 26;j++)                printf("%2d",next[i][j]);            printf("]\n");        }    }*/};Tree ac;char s[22],str[50];int main(){int cas=1;int n;while(~scanf("%d",&n)){if(n==0) break;ac.init();for(int i=0;i<n;i++){scanf("%s",s);ac.insert(s);}scanf("%s",str);ac.build();printf("Case %d: ",cas++);ac.solve(str);}}


0 0