题意 : 给出 m 个单词,每一个单词有一个权重,如果一个字符串包含了这些单词,那么意味着这个字符串拥有了其权重,问你构成长度为 n 且权重最大的字符串是什么 ( 若有权重相同的,则输出最短且字典序最小的 )

分析 : 如果你做过 POJ 2778 或者 HDU 2243 以及诸如此类的题目,那么这道题的难点就不在构建 Trie图上了,没有接触过Trie图的建议先了解,下面进入正题。这道题相对于普通的 AC自动机orTrie图 + DP 的题目而言,共同点是都是利用 Trie图进行状态的转移,现在增加了权重以及要求输出具体的字符串答案。我们定义 DP[i][j] 为构建了长度为 i 且最后一个字符为 j 的字符串最大权重,由于每一个状态都对应一个字符串,所以再构建一个三维字符数组 s[i][j][k] 表示当前 i、j 状态下具体的字符串为 s[i][j][0~k-1],那么状态转移方程就是

DP[i+1][ Trie[j][k] ] = max( DP[i+1][ Trie[j][k] ] , DP[i][j] + Trie[j][k].val )

( Trie[j][k] 代表 j 状态可以一步转移到 k状态,如果你做过类似题目,那你不会陌生)

在状态转移的时候需要时时更新 s[i][j][k] 这个三维数组,当取得更优值的时候需要更新,最后只要在DP的过程当中记录最优的权重、状态i、j下标然后DP结束后输出即可。当然有个小优化,这种DP属于向前的DP,如果当前DP值是你设置的初值,那么它是没意义的,可以直接continue,因为它不会对后面的DP值产生影响。

  1. #include<string.h>
  2. #include<stdio.h>
  3. #include<queue>
  4. using namespace std;
  5. ;
  6. ;
  7.  
  8. ][];
  9. ][][];///存储每一个状态所代表的具体字符串
  10.  
  11. struct Aho{
  12. struct StateTable{
  13. int Next[Letter];
  14. int fail, val;
  15. }Node[Max_Tot];
  16. int Size;
  17. queue<int> que;
  18.  
  19. inline void init(){
  20. while(!que.empty()) que.pop();
  21. memset(Node[].Next, , ].Next));
  22. Node[].fail = Node[].val = ;
  23. Size = ;
  24. }
  25.  
  26. inline void insert(char *s, int val){
  27. ;
  28. ; s[i]; i++){
  29. int idx = s[i] - 'a';
  30. if(!Node[now].Next[idx]){
  31. memset(Node[Size].Next, , sizeof(Node[Size].Next));
  32. Node[Size].fail = Node[Size].val = ;
  33. Node[now].Next[idx] = Size++;
  34. }
  35. now = Node[now].Next[idx];
  36. }
  37. Node[now].val = val;
  38. }
  39.  
  40. inline void BuildFail(){
  41. Node[].fail = ;
  42. ; i<Letter; i++){
  43. ].Next[i]){
  44. Node[Node[].Next[i]].fail = ;
  45. que.push(Node[].Next[i]);
  46. }].Next[i] = ;
  47. }
  48. while(!que.empty()){
  49. int top = que.front(); que.pop();
  50. Node[top].val += Node[Node[top].fail].val;///这里需要注意!
  51. ; i<Letter; i++){
  52. int &v = Node[top].Next[i];
  53. if(v){
  54. que.push(v);
  55. Node[v].fail = Node[Node[top].fail].Next[i];
  56. }else v = Node[Node[top].fail].Next[i];
  57. }
  58. }
  59. }
  60. }ac;
  61. ][];
  62. int main(void)
  63. {
  64. int nCase;
  65. scanf("%d", &nCase);
  66. while(nCase--){
  67. int n, m;
  68. scanf("%d %d", &n, &m);
  69. ; i<m; i++)
  70. scanf("%s", tmp[i]);
  71. int tmpVal;
  72. ac.init();
  73. ; i<m; i++){
  74. scanf("%d", &tmpVal);
  75. ac.insert(tmp[i], tmpVal);
  76. }
  77. ac.BuildFail();
  78.  
  79. ; i<=n; i++){///将所有DP的值赋为 -1
  80. ; j<ac.Size; j++){
  81. dp[i][j] = -;
  82. s[i][j][] = '\0';
  83. }
  84. }
  85.  
  86. dp[][] = ;///定义初始状态
  87.  
  88. ];
  89. int ii, jj, MaxSum;
  90. ii = jj = MaxSum = ;
  91. ; i<n; i++){
  92. ; j<ac.Size; j++){
  93. ){///如果当前dp值不是初始状态则进入if,否则其dp值毫无意义,直接跳过
  94. ; k>=; k--){///一开始我是想谋求字典序最小而从后往前,但是WA一发后我发现我错了,实际上顺序不重要
  95. ;
  96. int newj = ac.Node[j].Next[k];
  97. int sum = dp[i][j] + ac.Node[ newj ].val;
  98. if(sum > dp[newi][newj]){
  99. dp[newi][newj] = sum;
  100. strcpy(s[newi][newj], s[i][j]);
  101. int len = strlen(s[i][j]);
  102. s[newi][newj][len] = k+'a';
  103. s[newi][newj][len+] = '\0';
  104. }else if(sum == dp[newi][newj]){///谋求字典序最小应该实在dp值相等情况下
  105. strcpy(str, s[i][j]);
  106. int len = strlen(str);
  107. str[len] = 'a'+k;
  108. str[len+] = '\0';
  109. )
  110. strcpy(s[newi][newj], str);
  111. }
  112.  
  113. if(dp[newi][newj] >= MaxSum){///更新一下最终的答案
  114. if(dp[newi][newj] == MaxSum){
  115. int L1 = strlen(s[newi][newj]);
  116. int L2 = strlen(s[ii][jj]);
  117. )
  118. ii = newi, jj = newj;
  119. }else{
  120. MaxSum = dp[newi][newj];
  121. ii = newi, jj = newj;
  122. }
  123. }
  124.  
  125. }
  126. }
  127. }
  128. }
  129.  
  130. ) puts("");///如果最后权值依旧是 0 那么输出空串
  131. else puts(s[ii][jj]);
  132. }
  133. ;
  134. }

HDU 2296 Ring ( Trie图 && DP && DP状态记录)的更多相关文章

  1. HDU 2296 Ring (AC自动机+DP)

    Ring Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submis ...

  2. HDU 2296 Ring [AC自动机 DP 打印方案]

    Ring Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submissio ...

  3. BZOJ3530: [Sdoi2014]数数(Trie图,数位Dp)

    Description 我们称一个正整数N是幸运数,当且仅当它的十进制表示中不包含数字串集合S中任意一个元素作为其子串.例如当S=(22,333,0233)时,233是幸运数,2333.20233.3 ...

  4. HDU 2296:Ring

    Problem Description For the hope of a forever love, Steven is planning to send a ring to Jane with a ...

  5. HDU 2296 Ring -----------AC自动机,其实我想说的是怎么快速打印字典序最小的路径

    大冥神的代码,以后能贴的机会估计就更少了....所以本着有就贴的好习惯,= =....直接贴 #include <bits/stdc++.h> using LL = long long ; ...

  6. HDU 4511 小明系列故事——女友的考验 ( Trie图 && DP )

    题意 :  给出编号从1 ~ n 的 n 个平面直角坐标系上的点,求从给出的第一个点出发到达最后一个点的最短路径,其中有两种限制,其一就是只能从编号小的点到达编号大的点,再者不能走接下来给出的 m 个 ...

  7. HDU 4057 Rescue the Rabbit ( AC自动机 + 状态压缩DP )

    模板来自notonlysuccess. 模式串只有10个,并且重复出现的分值不累加,因此很容易想到状态压缩. 将模式串加入AC自动机,最多有10*100个状态. dp[i][j][k]:串长为i,在T ...

  8. POJ 1625 Censored ( Trie图 && DP && 高精度 )

    题意 : 给出 n 个单词组成的字符集 以及 p 个非法串,问你用字符集里面的单词构造长度为 m 的单词的方案数有多少种? 分析 :先构造出 Trie 图方便进行状态转移,这与在 POJ 2278 中 ...

  9. HDU 3341 Lost's revenge ( Trie图 && 状压DP && 数量限制类型 )

    题意 : 给出 n 个模式串,最后给出一个主串,问你主串打乱重组的情况下,最多能够包含多少个模式串. 分析 : 如果你做过类似 Trie图 || AC自动机 + DP 类似的题目的话,那么这道题相对之 ...

随机推荐

  1. Web UI自动化测试基础——元素定位(三)

    本篇文章整理了元素定位的基础知识——iframe框架中的元素定位. 一.iframe框架元素定位 iframe是Html页面的内联框架,如果在自动化测试中无法定位到某个元素,那么很有可能是因为该元素在 ...

  2. [Mac Terminal] ___MAC终端清屏快捷键

    清全屏: command + K 清上一行命令:command +  L

  3. 【Python】关于近期爬虫学习的总结

    写在开头 在之前的三篇文章中,我尝试了使用python爬虫实现的对于特定站点的<剑来>小说的爬取,对于豆瓣的短评的爬取,也有对于爬取的短评数据进行的词云展示,期间运用了不少的知识,现在是时 ...

  4. unittest中的断言方法

    方法        用途 assertEqual(a,b)      a=b assertNotEqual(a,b)    a!=b assertTrue(x)     x为True assertFa ...

  5. Hive-生成一个大文件(小文件合并)

    set hive.execution.engine=mr; --在 map-reduce 作业结束时合并小文件.如启用,将创建 map-only 作业以合并目标表/分区中的文件. set hive.m ...

  6. [19/10/14-星期一] Python中的对象和类

    一.面向对象 ## 什么是对象? - 对象是内存中专门用来存储数据的一块区域. - 对象中可以存放各种数据(比如:数字.布尔值.代码) - 对象由三部分组成: 1.对象的标识(id) 2.对象的类型( ...

  7. JS中同步与异步

    不讲过多定义,举两个例子说明下 例一: console.log(100); setTimeout(function(){ console.log(200); },1000); console.log( ...

  8. Aliyun-Centos 7 LNMP安装(最新版LNMP)

    linux装软件方式:1.源码安装:下载wget-->解压tar -zxvf -->配置 ./configure --->编译make -->安装 make install 2 ...

  9. PyCharm中运行同一个python程序时选择平行窗口运行

    问题描述 当我们进行Socket编程时,客户端可能有多个,原则上如果有n个客户端,那么我们就要编辑n客户端的代码.然而其实我们每个客户端的代码都是相同,如果编辑n遍,将会相当的浪费空间. 解决办法 学 ...

  10. Vue-cli3 简qian易yi教程

    原文地址 对于没有了解过 vue-cli3 的童鞋,建议先去看看官方的教程: 传送门 新版本的新特性 1. 插件 使用 cli 的插件,可以很快的搭建一个项目的结构.如 axios 的插件 vue-c ...