HDU 2296 Ring(AC自动机+DP)
来源:互联网 发布:淘宝可以卖虚拟物品吗 编辑:程序博客网 时间:2024/05/11 02:14
HDU 2296 Ring(AC自动机+DP)
http://acm.hdu.edu.cn/showproblem.php?pid=2296
题意:
给你M个单词构成一个词典,每个单词有一个权值(单词出现多次算多个权值),现在要你构造一个不超过长度N的字符串,使得该字符串权值最大。如果出现多个答案,输出最短的,如果依然有多解,输出字典序最小的。
分析:
本题和之前几题类似。不过注意这题的AC自动机要用match, match[i]表示i节点的后缀单词权值总和.后缀单词指的是:所有可以做i节点表示的串的后缀的单词.
令dp[i][j]=x表示当前在i点走过了长j的路所生产的最大权值为x. 再用string path[i][j]来保存那个具有最大权值的最优字符串即可.不过要注意如果最后算的的最大权值是0,那么要输出空串.因为空串最短.
dp[i][j] = max(dp[k][j-1]+match[i]) 若dp[i][j]更新的时候,path[i][j]也要看看是否需要更新成:
if(path[i][j]!=””)path[i][j] = better(path[i][j] , path[k][j-1]+”x”)x字符表示从k走到i的那条边的字符是x.
初值path=空串,dp[0][0]=0.
注意:做这题的时候出现了几个错误的地方.
首先对于dp[i][j]不可达的节点一定要置-1,不能置1
其次对于当dp[ch[k][j]][len + 1] <dp[k][len] + match[ch[k][j]]时直接替换原来的path,而不是求最优了.
还有HDU提交这题的时候我一直编辑错误,不知道错在哪里?后来不得不改掉一些函数了.后来经过无数次的测试,发现少些了#include<string> .
AC代码:
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#include<queue>#include<string>using namespace std;int N,M;const int maxnode=1000+100;const int sigma_size=26;inline string better(string a,string b){ if(a=="") return b; if(a.size()!=b.size()) return a.size()<b.size() ? a:b; return a<b? a:b;}struct AC_Automata{ int ch[maxnode][sigma_size]; int match[maxnode]; int f[maxnode]; int sz; int dp[maxnode][50+10]; string path[maxnode][50+10]; int ans; string res; void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); match[0]=f[0]=0; } void insert(char *s,int v) { int n=strlen(s),u=0; for(int i=0;i<n;i++) { int id=s[i]-'a'; if(ch[u][id]==0) { ch[u][id]=sz; memset(ch[sz],0,sizeof(ch[sz])); match[sz++]=0; } u=ch[u][id]; } match[u]=v; } void getFail() { queue<int> q; for(int i=0;i<sigma_size;i++) { int u=ch[0][i]; if(u) { f[u]=0; q.push(u); } } while(!q.empty()) { int r=q.front();q.pop(); for(int i=0;i<sigma_size;i++) { int u=ch[r][i]; if(!u){ ch[r][i]=ch[f[r]][i]; continue; } q.push(u); int v=f[r]; while(v && ch[v][i]==0) v=f[v]; f[u]=ch[v][i]; match[u] += match[f[u]]; } } } void solve() { ans=0; res=""; for(int i=0;i<sz;i++) for(int j=0;j<=N;j++) { dp[i][j]=-1; path[i][j]=""; } dp[0][0]=0; for(int len=0;len<N;len++)//当前走的长度 for(int k=0;k<sz;k++)if(dp[k][len]!=-1)//当前所在的节点 { for(int j=0;j<sigma_size;j++)//下一步走的方向 if(dp[ch[k][j]][len+1] <= dp[k][len]+match[ch[k][j]]) { char temp='a'+j; if(dp[ch[k][j]][len+1] < dp[k][len]+match[ch[k][j]]) { dp[ch[k][j]][len+1] = dp[k][len]+match[ch[k][j]]; path[ch[k][j]][len+1] = path[k][len]+temp; } else { path[ch[k][j]][len+1] = better(path[ch[k][j]][len+1],path[k][len]+temp); } if(ans < dp[ch[k][j]][len+1]) { ans = dp[ch[k][j]][len+1]; res = path[ch[k][j]][len+1]; } else if(ans == dp[ch[k][j]][len+1]) res = better(res,path[ch[k][j]][len+1]); } } }}ac;char str[100+10][10+5];int val[100+10];int main(){ int T; scanf("%d",&T); while(T--) { ac.init(); scanf("%d%d",&N,&M); for(int i=0;i<M;i++) scanf("%s",str[i]); for(int i=0;i<M;i++) { scanf("%d",&val[i]); ac.insert(str[i],val[i]); } ac.getFail(); ac.solve(); if(ac.ans==0) printf("\n"); else cout<<ac.res<<endl; } return 0;}
- HDU 2296 Ring(AC自动机+DP)
- HDU 2296 Ring(AC自动机+DP)
- HDU 2296 Ring(AC自动机+DP)
- 【HDU】2296 Ring AC自动机+DP
- hdu 2296 Ring(AC自动机+DP)
- hdu 2296 Ring AC自动机+DP
- hdu 2296 Ring (ac自动机+dp)
- HDU 2296 Ring(AC自动机+dp)
- HDU 2296 Ring (AC自动机 + DP)
- 【hdu 2296】 Ring AC-自动机+DP
- hdu 2296 Ring AC自动机+DP
- hdu 2296 Ring(AC自动机+DP)
- HDU 2296 Ring (AC自动机+DP)
- HDU 2296-Ring(AC自动机+DP)
- HDU 2296 Ring(AC自动机+DP)
- HDU 2296 Ring (AC自动机+DP,5级)
- HDU 2296 Ring(AC自动机 + DP 记录方案)
- HDU 2296 Ring AC自动机上的DP
- iOS对象代理的问题
- IIS Express 简介
- Qualification Round 2014 Minesweeper Master small 版
- C++primer plus第六版课后编程题答案9.3
- 硬币问题 动态规划 算法入门经典
- HDU 2296 Ring(AC自动机+DP)
- ftghj
- ListView 上下移动行
- 通过字符串来使用R下面资源的ID 值
- scut1109幸运儿 (约瑟夫环)
- 联合体(union)的使用方法及其本质
- 计算机视觉的一流人物
- 关于抽象类和接口的学习总结一
- POJ-1182 食物链 经典并查集