[AC自动机+dp+变进制状压] hdu 3341 Lost's revenge
来源:互联网 发布:怎么查自己的淘宝账号 编辑:程序博客网 时间:2024/06/05 15:42
题意思路摘自大神:http://www.cppblog.com/menjitianya/archive/2014/07/11/207604.html#207622
题意:给定N(N <= 50)个长度不超过10的模式串(ACGT串),再给定一个长度为M(M <= 40)的目标串S,求将目标串重排列,使得它包含最多的模式串,求这个最多的数目。
题解:利用模式串建立trie图,trie图上最多有500个结点( N*10 ),然后朴素的思想就是用S(i, iA, iC, iG, iT)表示在i状态下,拥有iA个A、iC个C、iG个G、iT个T的串拥有的最多的模式串的个数,但是iA, iC, iG, iT的取值均是[0, 40],所以我们需要把状态压缩一下,我们知道当四种字符都取10的时候可以让状态数达到最大,即114 = 14641, 所以可以令MaxA、
MaxC、MaxG、MaxT分别表示四种字符出现的个数,那么T字符的权值为1,G字符的权值为(MaxT + 1),C字符的权值为(MaxG + 1) *(MaxT + 1),A字符的权值为(MaxC + 1) *(MaxG + 1) *(MaxT + 1),进行进制压缩之后总的状态数不会超过114,可以用DP[i][j]表示在trie的i号结点时ACGT四个字符个数的压缩状态为j时的字符串包含模式串的最多数目,然后就是进行O(4*500*114)的状态转移了。
代码:
#include"cstdlib"#include"cstdio"#include"cstring"#include"cmath"#include"queue"#include"algorithm"#include"map"#include"iostream"using namespace std;int triecont;char fuck[55];struct trie{ int mark,id; trie *next[6],*fail; trie() { mark=id=0; memset(next,0,sizeof(next)); fail=NULL; }};trie *root,*node[520];int getid(char x){ if(x=='A') return 0; if(x=='C') return 1; if(x=='G') return 2; return 3;}void init(char *v){ trie *p=root; for(int i=0; v[i]; i++) { int tep=getid(v[i]); if(p->next[tep]==NULL) { p->next[tep]=new trie(); node[triecont]=p->next[tep]; p->next[tep]->id=triecont++; } p=p->next[tep]; } p->mark++;}void getac(){ queue<trie*>q; q.push(root); while(!q.empty()) { trie *p=q.front(); q.pop(); for(int i=0; i<4; i++) { if(p->next[i]==NULL) { if(p==root) p->next[i]=root; else p->next[i]=p->fail->next[i]; } else { if(p==root) p->next[i]->fail=root; else p->next[i]->fail=p->fail->next[i]; q.push(p->next[i]); if(p!=root) p->next[i]->mark+=p->next[i]->fail->mark; } } }}int dp[520][15000];int main(){ int n,cas=1; while(scanf("%d",&n),n) { memset(node,0,sizeof(node)); triecont=0; root=new trie(); node[triecont]=root; root->id=triecont++; while(n--) { char x[123]; scanf("%s",x); init(x); } getac(); scanf("%s",fuck); int used[12],bit[12]; memset(used,0,sizeof(used)); memset(bit,0,sizeof(bit)); for(int i=0; fuck[i]; i++) { used[getid(fuck[i])]++; } bit[0]=(used[3]+1)*(used[2]+1)*(used[1]+1); bit[1]=(used[3]+1)*(used[2]+1); bit[2]=(used[3]+1); bit[3]=1; memset(dp,-1,sizeof(dp)); dp[0][0]=0; for(int A=0; A<=used[0]; A++) { for(int B=0; B<=used[1]; B++) { for(int C=0; C<=used[2]; C++) { for(int D=0; D<=used[3]; D++) { int tep=A*bit[0]+B*bit[1]+C*bit[2]+D*bit[3]; for(int j=0; j<triecont; j++) { if(dp[j][tep]!=-1) { for(int k=0;k<4;k++) { if(k==0 && used[0]==A) continue; if(k==1 && used[1]==B) continue; if(k==2 && used[2]==C) continue; if(k==3 && used[3]==D) continue; trie *p=node[j]->next[k]; dp[p->id][tep+bit[k]]=max(dp[p->id][tep+bit[k]],dp[j][tep]+p->mark); } } } } } } } int ans=0; int lit=used[0]*bit[0]+used[1]*bit[1]+used[2]*bit[2]+used[3]*bit[3]; for(int i=0;i<triecont;i++) ans=max(ans,dp[i][lit]); printf("Case %d: %d\n",cas++,ans); } return 0;}
0 0
- [AC自动机+dp+变进制状压] hdu 3341 Lost's revenge
- hdu 3341 Lost's revenge(AC自动机+变进制状压DP)
- HDU 3341 Lost's revenge AC自动机 + 变进制状压DP
- hdu 3341 Lost's revenge(AC自动机+DP)
- HDU 3341 Lost's revenge(AC自动机+DP)
- 【HDU】3341 Lost's revenge AC自动机+变进制+DP
- Hdu 3341 Lost's revenge (ac自动机+dp+hash)
- HDU - 3341 Lost's revenge(AC自动机+DP)
- hdu 3341 Lost's revenge (ac自动机+状压dp)
- hdu 3341Lost's revenge(ac自动机+dp)
- hdu 3341 Lost's revenge(dp+Ac自动机)
- HDU 3341 Lost's revenge (AC自动机 + DP)
- HDU 3341-Lost's revenge(AC自动机+DP+hash)
- HDU 3341 Lost's revenge (AC自动机+DP,5级)
- HDU 3341 Lost's revenge(AC自动机+状态压缩DP)
- HDU 3341 Lost's revenge(AC自动机+DP+变进制优化)
- HDU 3341 Lost's revenge (AC自动机 + dp[优化好多= =])
- 【AC自动机】 HDOJ 3341 Lost's revenge
- 使用C#编写JavaScript,Saltarelle库的使用
- Android开发:使用DDMS Heap进行内存泄露调试
- Web前端开发规范(二)
- phpcms出现登录总是提示超时需重新登录
- 最简单的贝叶斯分类器MATLAB实现
- [AC自动机+dp+变进制状压] hdu 3341 Lost's revenge
- DedeCMS列表页内容根据权重排序dede_arctiny 按weight排序
- linux 下无密码文件传输
- Call to undefined function imagecreate()
- Hasen的linux设备驱动开发学习之旅--支持多设备的字符设备驱动
- 远程连接
- 路由器和交换机的原理分别是什么
- 算法篇之排序(二)
- Python 正则表达式验证IPv4地址