hdu4057(ac自动机,状态压缩dp)
来源:互联网 发布:淘宝客服售后处理流程 编辑:程序博客网 时间:2024/05/16 15:31
Rescue the Rabbit
Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1790 Accepted Submission(s): 512
A rabbit's genes can be expressed as a string whose length is l (1 ≤ l ≤ 100) containing only 'A', 'G', 'T', 'C'. There is no doubt that Dr. X had a in-depth research on the rabbits' genes. He found that if a rabbit gene contained a particular gene segment, we could consider it as a good rabbit, or sometimes a bad rabbit. And we use a value W to measure this index.
We can make a example, if a rabbit has gene segment "ATG", its W would plus 4; and if has gene segment "TGC", its W plus -3. So if a rabbit's gene string is "ATGC", its W is 1 due to ATGC contains both "ATG"(+4) and "TGC"(-3). And if another rabbit's gene string is "ATGATG", its W is 4 due to one gene segment can be calculate only once.
Because there are enough rabbits on Earth before 2012, so we can assume we can get any genes with different structure. Now Dr. X want to find a rabbit whose gene has highest W value. There are so many different genes with length l, and Dr. X is not good at programming, can you help him to figure out the W value of the best rabbit.
The next n lines each line contains a string DNAi and an integer wi (|wi| ≤ 100), indicating this gene segment and the value it can contribute to a rabbit's W.
2 4ATG 4TGC -31 6TGC 44 1A -1T -2G -3C -4
44No Rabbit after 2012!Hintcase 1:we can find a rabbit whose gene string is ATGG(4), or ATGA(4) etc.case 2:we can find a rabbit whose gene string is TGCTGC(4), or TGCCCC(4) etc.case 3:any gene string whose length is 1 has a negative W.
题意:给出一些模式串,每个串有一定的价值,现在要构造一个长度为M的串,问最大的价值为多少,每个模式串最多统计一次。
首先涉及到了字符串的匹配,要用到ac自动机,其次,求最大价值那么就要用状态压缩dp来解决了。网上的各种博客并没有一个把这一题讲解的很清晰的。。
首先来说ac自动机吧,建立ac自动机我用的二维数组模拟,用val[]数组来表示每一个子串的结束(可是存的数并不是1,2,3,4,5……这些,因为我们后边要用到状态压缩dp,那么这里我用2^i,也就是代码里的1<<i来表示,为何要这样表示?我们用位运算来模拟总共这n个子串如果存在就是1,不存在就是0,那么我们现在每个子串的结尾用2^i表示,我们想想,把2^i转化为2进制之后,是不是恰好都是只有1个1?这样来精确的表示存在第i个字串,这里跟后面的状态压缩dp有非常大的关联)
然后是建立自动机的过程,与正常的建立差不多,只不过也是val数组有变动,因为相当于在一个子串结束了恰好接上另一个子串的时候,难道val[]不变吗?如果不变那么我们建立ac自动机就没意义了。试想我们用val[ ch[p][i] ] | = val[ f [ ch [p][i] ] ];(f[]数组是失配指针数组),为何要用或?因为一个子串的尾节点的val值一定是1到1<<n之间的化为二进制只有一位为1的某数,现在它连接了另一个单词,那么在二进制里面又加上了另一个单词,不过val里边却只有一个1,这样我们用或的位运算来恰好接上另一个1来表示两个子串的相连。
然后是dp部分,我们用dp[i][j][k]表示状态,就是要构造长度为i的到了ac自动机里第j个节点的对应状态为k的(当然k一定要用二进制的眼光来看,0表示某个子串不存在,1表示存在)状态是否成立,如果成立,那么让他等于1,否则继续。
if(dp[(i+1)&1][j][hh]) dp[i&1][ch[j][k]][hh|val[ch[j][k]]]=1;
这是dp部分的精华,因为上一个状态成立的之后,代表下一个状态能推出来的状态也必然成立,推出来的val[ch[j][k]]就是我介绍为什么要按上面的方式存储val的原因,它记录了某一个节点包含多少个子串的全部信息(当然是转化为二进制之后,为1代表有,0代表没有咯)
当然,由于空间不能开爆内存,所以采取滚动数组的方式,将dp[i][j][k]的i只开了2,,相当于模拟,同时大幅减小了内存。
#include <iostream>#include <stdio.h>#include <stdlib.h>#include<string.h>#include<algorithm>#include<math.h>#include<queue>using namespace std;typedef long long ll;const int CH =4,NODE = 1005;int m,n;int idx(char x){ if(x=='A')return 0; else if(x=='C')return 1; else if(x=='G')return 2; return 3;}int ch[NODE][CH],f[NODE],val[NODE],sz,v[NODE];int node(){ memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; return sz++;}void init(){ sz=0; node(); memset(f,0,sizeof(f));}void ins(char *s,int i){ int u=0; for(; *s; s++) { int c=idx(*s); if(!ch[u][c]) ch[u][c]=node(); u=ch[u][c]; } val[u]=1<<i;}int queu[NODE];void getfail(){ int l=0,r=0; queu[r++]=0; while(l<r) { int p=queu[l++]; for(int i=0; i<4; i++) { if(ch[p][i]==0) ch[p][i]=ch[f[p]][i]; else { int q=ch[p][i]; if(p) f[q]=ch[f[p]][i]; val[q]|=val[f[q]]; queu[r++]=q; } } }}bool dp[2][1005][1<<10];int get(int x){ int ans=0; for(int i=0; i<(1<<n); i++) if(x&(1<<i))//这里的位运算也非常巧妙 ans+=v[i]; return ans;}void solve(){ 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<=sz; j++) { for(int k=0; k<4; k++) { for(int hh=0; hh<(1<<n); hh++) if(dp[(i+1)&1][j][hh]) dp[i&1][ch[j][k]][hh|val[ch[j][k]]]=1; } } } int ans=-999999999; for(int i=0; i<=sz; i++) for(int j=0; j<(1<<n); j++) if(dp[m&1][i][j]) ans=max(ans,get(j)); if(ans<0) printf("No Rabbit after 2012!\n"); else printf("%d\n",ans);}int main(){ while(~scanf("%d%d",&n,&m)) { init(); for(int i=0; i<n; i++) { char ss[105]; scanf("%s%d",ss,&v[i]); ins(ss,i); } getfail(); solve(); } return 0;}
- hdu4057(ac自动机,状态压缩dp)
- hdu4057(AC自动机+状态压缩dp)
- hdu4057 Rescue the Rabbit,AC自动机,状态压缩dp
- hdu4758 hdu2825 hdu4057 AC自动机与状态压缩dp的结合
- AC自动机(hdu4057)
- hdu2852(ac自动机,状态压缩dp)
- hdu4758(ac自动机,状态压缩dp)
- hdu4057 Rescue the Rabbit(AC自动机+DP)
- hdu4057 ac自动机+dp(我用的方法)
- HDU 2825 Wireless Password (AC自动机 + 状态压缩DP)
- HDU 2825 Wireless Password (AC自动机+DP+状态压缩)
- [HDU 2825] Wireless Password (AC自动机+状态压缩DP)
- HDU 3247 AC自动机 + 状态压缩dp
- HDU 4534(ac自动机+状态压缩dp)
- hdu 2825 ac自动机+状态压缩dp
- AC自动机+状态压缩DP+hdu2825
- hdu2825 AC自动机+状态压缩DP
- hdu 4057 AC自动机+状态压缩dp
- mmap发生Bus error
- 损失函数(Loss Function)
- 源码:自己用Python写的iOS项目自动打包脚本
- 关于 @synchronized,这儿比你想知道的还要多
- SpringMVC RESTful 性能优化
- hdu4057(ac自动机,状态压缩dp)
- spring jdbc 及代理模式
- 整合Activiti Modeler到业务系统(或BPM平台)
- 关于原始类型和引用类型被当作集合类型使用
- 查看Security Context
- Linux ipcs 命令详解
- linux route命令的使用详解
- java代码实现ping ip
- 使用sqlite3与C接口开发数据库程序