hdu 4057 Rescue the Rabbit AC自动机+DP

来源:互联网 发布:mac地址克隆失败 编辑:程序博客网 时间:2024/05/16 01:13

http://acm.hdu.edu.cn/showproblem.php?pid=4057


11年大连站的题目,在现场已经算是简单题了。。。


给出N(N<=10)个串,每个串都有个权值Wi,|Wi|<100。如果一个串出现了给定的串,那么权值就加上那个W,但只能加一次。现在问你长度为L(L<=100)的串的最大权值是多少?


构造AC自动机,然后DP就好了,DP[100][1000][1024],dp[i][j][k]表示长度为i的串,匹配到自动机中j号节点的状态,串出现的状态二进制表示为k时是否可达。


这时候很容易根据每个状态来转移,但是空间开不下,可以开滚动数组把第一维拿掉。这样就够了。。。大概10^8的算法,10s已经够了。。。


如果写成Trie图会更快点。。。。我的代码500ms


#include<cstdio>#include<cstring>#include<iostream>#include<queue>using namespace std;const int maxn = 1001;const int INF = 0x3ffffff;struct Node{int ch[4],pre;int b;}node[maxn];int top;int root;int val[11];int nw(){memset(node[top].ch,0,sizeof(node[top].ch));node[top].pre=0;node[top].b=0;return top++;}int tran(char c){if(c=='A')return 0;else if(c=='T')return 1;else if(c=='G')return 2;else return 3;}char str[100000];queue<int>q;void bfs(){q.push(root);while(!q.empty()){int u=q.front();q.pop();for(int i=0;i<4;i++){int p=node[u].pre;if(node[u].ch[i]){int v=node[u].ch[i];if(u==root)node[v].pre=root;else {node[v].pre=node[p].ch[i];node[v].b|=node[node[p].ch[i]].b;}q.push(node[u].ch[i]);}else{if(u==root)node[u].ch[i]=root;else {node[u].ch[i]=node[p].ch[i];//node[u].b|=node[node[p].ch[i]].b;}}}}}bool dp[2][1010][1024];int main(){int n,l;while(~scanf("%d%d",&n,&l)){top=0;root=nw();for(int i=0;i<n;i++){scanf("%s",str);int len=strlen(str);int p=root;if(len>l){scanf("%d",&val[i]);continue;}for(int j=0;j<len;j++){int c=tran(str[j]);if(node[p].ch[c]==0){node[p].ch[c]=nw();}p=node[p].ch[c];}node[p].b=node[p].b|(1<<i);scanf("%d",&val[i]);}bfs();int cur=0;for(int i=0;i<top;i++){for(int j=0;j<1<<n;j++){dp[cur][i][j]=false;}}dp[cur][0][0]=true;for(int k=0;k<l;k++){int next=(cur+1)%2;for(int i=0;i<top;i++){for(int j=0;j<1<<n;j++){dp[next][i][j]=false;}}for(int i=0;i<top;i++){for(int j=0;j<1<<n;j++){if(dp[cur][i][j]==false)continue;for(int t=0;t<4;t++){int to=node[i].ch[t];int bb=j|node[to].b;dp[next][to][bb]=true;}}}cur=next;}int ans=-1;for(int i=0;i<top;i++){for(int j=0;j<1<<n;j++){if(dp[cur][i][j]){int sum=0;for(int k=0;k<n;k++){if(j&(1<<k))sum+=val[k];}ans=max(sum,ans);}}}if(ans<0)printf("No Rabbit after 2012!\n");else printf("%d\n",ans);}}


原创粉丝点击