转载请注明出处,谢谢http://blog.csdn.net/acm_cxlove/article/details/7854526 by---cxlove
题目:给出一些模式串,每个串有一定的价值,现在构造一个长度为M的串,问最大的价值为多少,每个模式串最多统计一次。
http://acm.hdu.edu.cn/showproblem.php?pid=4057
11年大连现场赛的题目,不算非常难。
由于每个模式串最多统计一次,也算是降低了难度,最多10个串,容易想至于状态压缩。
Trie树上的状态最多1000个,100*10,而最终的串长度最多为100
容易想到的DP,dp[i][j][k],表示长度为i的串,位于Trie上的状态j,模式串的状态为k的最大价值。
这个复杂度为100*1024*1000,题目给了10s,还是可以搞的,但是空间不够,只能用滚动数组了。
先建立Trie树,以及失败指针,对于每一个结点,标号,静态的方便点。
最终DP,通过模式串的状态确定当前价值
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #define eps 1e-10 #define N 100005 #define inf 1<<20 #define zero(a) (fabs(a)<eps) #define lson (step<<1) #define rson (step<<1|1) using namespace std; struct Trie{ int next[4],fail; int end; void Init(){next[0]=next[1]=next[2]=next[3]=0;fail=end=0;} }tree[N]; int dp[2][1005][1<<10]; char str[105]; int val[105],tot; int id(char ch){ if(ch=='A') return 0; if(ch=='T') return 1; if(ch=='G') return 2; return 3; } void Insert(char *s,int len,int k){ int p=0; for(int i=0;i<len;i++){ int q=id(s[i]); if(tree[p].next[q]==0){ tree[++tot].Init(); tree[p].next[q]=tot; } p=tree[p].next[q]; } tree[p].end|=(1<<k); } void Bulid_Fail(){ int que[N]; int head=0,tail=0; que[tail++]=0; while(head<tail){ int p=que[head++]; for(int i=0;i<4;i++){ if(tree[p].next[i]==0) tree[p].next[i]=tree[tree[p].fail].next[i]; else{ int q=tree[p].next[i]; if(p) tree[q].fail=tree[tree[p].fail].next[i]; tree[q].end|=tree[tree[q].fail].end; que[tail++]=q; } } } } int n,m; int get(int state){ int ans=0; for(int i=0;i<n;i++) if(state&(1<<i)) ans+=val[i]; return ans; } void DP(){ memset(dp,0,sizeof(dp)); dp[0][0][0]=1; for(int i=1;i<=m;i++){ memset(dp[i&1],0,sizeof(dp[i&1])); for(int j=0;j<=tot;j++){ for(int k=0;k<4;k++){ for(int r=0;r<(1<<n);r++){ if(dp[(i+1)&1][j][r]) dp[i&1][tree[j].next[k]][r|tree[tree[j].next[k]].end]=1; } } } } int ans=-inf; for(int j=0;j<(1<<n);j++) for(int i=0;i<=tot;i++) if(dp[m&1][i][j]){ ans=max(ans,get(j)); break; } if(ans<0) puts("No Rabbit after 2012!"); else printf("%d\n",ans); } int main(){ freopen("1.in","r",stdin); freopen("2.out","w",stdout); while(scanf("%d%d",&n,&m)!=EOF){ tree[0].Init();tot=0; for(int i=0;i<n;i++){ scanf("%s%d",str,&val[i]); Insert(str,strlen(str),i); } Bulid_Fail(); DP(); } return 0; }