题目直接链接

分析一下:

  这题题意还是比较明白的(少见的一道中文题),他的意思就是:有这么一个无向图:保证联通且点与点直接有唯一的简单路径(说白了就是棵树,根节点是1),每个节点有一个权值(有正有负)和最多经过的次数(>=2),求从根到根的走法中能拿到的最大权值(每个权值只能拿一次,根没有权值,且不限次数)。

  题意还是这么长。。。不过其实每一句话都是比较通俗的,大家应该都能理解题意。

  既然是一棵树,那就先想一想有关树的东西(不过思维不要僵化,也不一定就用有关树的知识),显然最小生成树,倍增lca啥的没啥用,而且求最优很容易想到dp,但是到底行不行呢,还是要试试嘛。

  我们想一想,这个次数可以限制什么呢?首先你要想到这里回去,就要使用一次停留的次数,如果你还要再去一个儿子,那么你还要多停留一次,同理,去两个就要多停留两次。注意,是多停留,也就是说原先的一次该停还是还是要停的,于是,我们就可以从儿子里面选择次数-1个最优的加进去,可是儿子最优的要哪里来呢,提前处理出来,诶,有感觉了Dfs加Dp,也就是树形Dp(其实这里并不是很纯正的Dp,因为可能会t掉,所以稍有不同)。

  基本的思路有了,那我们来想一下怎么转移状态,当然转移前要先定义好,这个的定义应该很简单:Dp[i]表示加入i之后可以加的最大权值。那Dp[i]=max(0,前次数-1大的儿子的最优之和(有一点点贪心的感觉)+i的权值),貌似还挺好写的,但是怎么找到前次数-1大的儿子的最优呢?这个就是代码能力的问题了。。。这里处理方法很多:可以维护一个堆,然后一个一个push进去(因为要边进行dfs边push,所以加一个参数,重定义一下<就好了),也可以Dfs和处理分开,先dfs,然后再处理,这样就不会出现覆盖前面数据的问题了,还有就是,可以我开一个n的数组,然后边dfs边分配内存,也可以,当然,给每一个节点开一个数组就不太好了,你也开不下。

  好了??其实才一半,还要输出有没有多解呢,先看一个错误代码(这里的数据真的有一点水)

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. const int maxn=+;
  5. int val[maxn];
  6. int cs[maxn];
  7. int Dp[maxn];
  8. int jl[maxn];
  9. bool Dj[maxn];
  10. struct E{
  11. int to;
  12. int next;
  13. int tree;
  14. E(){
  15. to=next=;
  16. tree=;
  17. }
  18. }ed[maxn*];
  19. int head[maxn];
  20. int tot;
  21. int cfr;
  22. void J(int a,int b){
  23. tot++;
  24. ed[tot].to=b;
  25. ed[tot].next=head[a];
  26. head[a]=tot;
  27. }
  28. bool Cm(int a,int b){
  29. return Dp[a]<Dp[b];
  30. }
  31. void Dfs(int a){
  32. int js=cfr;
  33. int fr=cfr;
  34. for(int i=head[a];i;i=ed[i].next)
  35. if(ed[i].tree){
  36. js++;
  37. jl[js]=ed[i].to;
  38. }
  39. cfr=js;
  40. for(int i=head[a];i;i=ed[i].next)
  41. if(ed[i].tree){
  42. ed[i%?(i+):(i-)].tree=;
  43. Dfs(ed[i].to);
  44. }
  45. if(js==fr){
  46. Dp[a]=max(,val[a]);
  47. if(val[a]==)
  48. Dj[a]=;
  49. return;
  50. }
  51. sort(jl++fr,jl+js+,Cm);
  52. int ans=;
  53. bool dj=;
  54. int E=fr;
  55. for(int i=js;i>fr&&js-i+<=cs[a]-;i--){
  56. ans+=Dp[jl[i]];
  57. dj|=Dj[jl[i]];
  58. E=i;
  59. }
  60. if(ans+val[a]<)
  61. return;
  62. if(!(ans+val[a])){
  63. Dj[a]=;
  64. return;
  65. }
  66. else{
  67. Dp[a]=val[a]+ans;
  68. Dj[a]=dj;
  69. }
  70. }
  71. int main(){
  72. int n;
  73. scanf("%d",&n);
  74. for(int i=;i<=n;i++)
  75. scanf("%d",&val[i]);
  76. for(int i=;i<=n;i++)
  77. scanf("%d",&cs[i]);
  78. cs[]=maxn;
  79. int js1,js2;
  80. for(int i=;i<=n-;i++){
  81. scanf("%d%d",&js1,&js2);
  82. J(js1,js2);
  83. J(js2,js1);
  84. }
  85. Dfs();
  86. printf("%d\n",Dp[]);
  87. if(Dj[])
  88. printf("solution is not unique");
  89. else
  90. printf("solution is unique");
  91. return ;
  92. }

错的ac代码

这个竟然过了。。。大家可以看看有什么问题,我也不再加注释了

能卡掉它的数据:

5
2 2 2 2
2 2 2 2
1 2
1 3
2 4
2 5

正确:

6

solution is not unique

它的输出:

6

solution is unique

大家可不要学。。。

好了,那我们到底怎么判断有无多解呢?

选择的儿子有多解,它有多解。不选的儿子与选的相同,有多解。选出0来,有多解。

所以代码是?:

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. const int maxn=+;
  5. int val[maxn];
  6. int cs[maxn];
  7. int Dp[maxn];
  8. int jl[maxn];
  9. bool Dj[maxn];
  10. struct E{
  11. int to;
  12. int next;
  13. int tree;
  14. E(){
  15. to=next=;
  16. tree=;
  17. }
  18. }ed[maxn*];
  19. int head[maxn];
  20. int tot;
  21. int cfr;
  22. void J(int a,int b){
  23. tot++;
  24. ed[tot].to=b;
  25. ed[tot].next=head[a];
  26. head[a]=tot;
  27. }
  28. bool Cm(int a,int b){
  29. return Dp[a]<Dp[b];
  30. }
  31. void Dfs(int a){
  32. int js=cfr;
  33. int fr=cfr;
  34. for(int i=head[a];i;i=ed[i].next)
  35. if(ed[i].tree){
  36. js++;
  37. jl[js]=ed[i].to;
  38. }
  39. cfr=js;
  40. for(int i=head[a];i;i=ed[i].next)
  41. if(ed[i].tree){
  42. ed[i%?(i+):(i-)].tree=;
  43. Dfs(ed[i].to);
  44. }
  45. if(js==fr){
  46. Dp[a]=max(,val[a]);
  47. if(val[a]==)
  48. Dj[a]=;
  49. return;
  50. }
  51. sort(jl++fr,jl+js+,Cm);
  52. int ans=;
  53. bool dj=;
  54. int E=fr;
  55. for(int i=js;i>fr&&js-i+<=cs[a]-;i--){
  56. ans+=Dp[jl[i]];
  57. dj|=Dj[jl[i]];
  58. E=i;
  59. }
  60. if(ans+val[a]<)
  61. return;
  62. if(!(ans+val[a])){
  63. Dj[a]=;
  64. return;
  65. }
  66. else{
  67. Dp[a]=val[a]+ans;
  68. Dj[a]=dj;
  69. if(E>fr+&&Dp[jl[E]]==Dp[jl[E-]]&&(Dp[jl[E]]||Dj[jl[E]]))
  70. Dj[a]=;
  71. if(!Dp[jl[E]])
  72. for(int i=E-;i>fr;i--)
  73. if(!Dp[jl[i]]&&Dj[jl[i]])
  74. Dj[a]=;
  75. }
  76. }
  77. int main(){
  78. int n;
  79. scanf("%d",&n);
  80. for(int i=;i<=n;i++)
  81. scanf("%d",&val[i]);
  82. for(int i=;i<=n;i++)
  83. scanf("%d",&cs[i]);
  84. cs[]=maxn;
  85. int js1,js2;
  86. for(int i=;i<=n-;i++){
  87. scanf("%d%d",&js1,&js2);
  88. J(js1,js2);
  89. J(js2,js1);
  90. }
  91. Dfs();
  92. printf("%d\n",Dp[]);
  93. if(Dj[])
  94. printf("solution is not unique");
  95. else
  96. printf("solution is unique");
  97. return ;
  98. }

其实还是有问题,不过那个都过了,这个按理说也能过。。。

问题在哪里,大家仔细研究一下,这个问题有点难发现。。。

好的,最后是最后的代码(终于有注释了):

  1. #include <cstdio>
  2. #include <algorithm>
  3. using namespace std;
  4. const int maxn=+;
  5. int val[maxn];
  6. int cs[maxn];
  7. int Dp[maxn];
  8. int jl[maxn];//排序用
  9. bool Dj[maxn];
  10. struct E{
  11. int to;
  12. int next;
  13. int tree;
  14. E(){
  15. to=next=;
  16. tree=;
  17. }
  18. }ed[maxn*];
  19. int head[maxn];
  20. int tot;
  21. int cfr;
  22. void J(int a,int b){
  23. tot++;
  24. ed[tot].to=b;
  25. ed[tot].next=head[a];
  26. head[a]=tot;
  27. }
  28. bool Cm(int a,int b){
  29. return Dp[a]<Dp[b];
  30. }
  31. void Dfs(int a){
  32. int js=cfr;
  33. int fr=cfr;
  34. for(int i=head[a];i;i=ed[i].next)
  35. if(ed[i].tree){
  36. js++;
  37. jl[js]=ed[i].to;
  38. }
  39. cfr=js;//先提前“申请空间”。
  40. for(int i=head[a];i;i=ed[i].next)
  41. if(ed[i].tree){
  42. ed[i%?(i+):(i-)].tree=;
  43. Dfs(ed[i].to);
  44. }
  45. if(js==fr){//叶子节点,特判掉
  46. Dp[a]=max(,val[a]);
  47. if(val[a]==)
  48. Dj[a]=;
  49. return;
  50. }
  51. sort(jl++fr,jl+js+,Cm);
  52. int ans=;
  53. bool dj=;
  54. int E=fr;
  55. for(int i=js;i>fr&&js-i+<=cs[a]-;i--){
  56. ans+=Dp[jl[i]];
  57. dj|=Dj[jl[i]];//记录有无多解
  58. E=i;
  59. }
  60. if(ans+val[a]<)//0都不到,直接不走它,也没多解
  61. return;
  62. if(!(ans+val[a])){//是0,有多解(走与不走)
  63. Dj[a]=;
  64. return;
  65. }
  66. else{//大于0
  67. Dp[a]=val[a]+ans;
  68. Dj[a]=dj;
  69. if(E>fr+&&Dp[jl[E]]==Dp[jl[E-]]&&(Dp[jl[E]]||Dj[jl[E]]))//如果儿子有相同的(注意,相同的0还要特殊处理)
  70. Dj[a]=;
  71. if(!Dp[jl[E]])//是0
  72. for(int i=E-;i>fr;i--)//找一遍看看有没有多解的0
  73. if(!Dp[jl[i]]&&Dj[jl[i]])
  74. Dj[a]=;
  75. }
  76. }
  77. int main(){
  78. int n;
  79. scanf("%d",&n);
  80. for(int i=;i<=n;i++)
  81. scanf("%d",&val[i]);
  82. for(int i=;i<=n;i++)
  83. scanf("%d",&cs[i]);
  84. cs[]=maxn;
  85. int js1,js2;
  86. for(int i=;i<=n-;i++){
  87. scanf("%d%d",&js1,&js2);
  88. J(js1,js2);
  89. J(js2,js1);
  90. }
  91. Dfs();
  92. printf("%d\n",Dp[]);
  93. if(Dj[])
  94. printf("solution is not unique");
  95. else
  96. printf("solution is unique");
  97. return ;
  98. }

salesman,动态规划带一点点贪心。的更多相关文章

  1. Work Scheduling(带反悔的贪心)

    https://www.luogu.org/problem/P2949 题目描述 Farmer John has so very many jobs to do! In order to run th ...

  2. HDU 1735 字数统计(模拟+一点点贪心的思想)

    题目戳我 字数统计 Time Limit: 1000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total S ...

  3. 带"反悔"的贪心-超市

    题面:https://www.acwing.com/problem/content/description/147/ 超市里有N件商品,每个商品都有利润pi和过期时间di,每天只能卖一件商品,过期商品 ...

  4. BZOJ2151 种树(贪心+堆+链表/wqs二分+动态规划)

    dp容易想到,但没法进一步优化了. 考虑贪心,每次选出价值最大的物品.但这显然是不对的因为会影响其他物品的选择. 于是考虑加上反悔操作.每次选出一个物品后,将其相邻两物品删除,再将原物品价值变为相邻两 ...

  5. 【1】【经典回溯、动态规划、贪心】【leetcode-55】跳跃游戏

    给定一个非负整数数组,你最初位于数组的第一个位置. 数组中的每个元素代表你在该位置可以跳跃的最大长度. 判断你是否能够到达最后一个位置. 示例 1: 输入: [2,3,1,1,4]输出: true解释 ...

  6. 终拿字节Offer...动态规划复盘...

    大家好!我是 Johngo 呀! 和大家一起刷题不快不慢,没想到已经进行到了第二阶段,「动态规划」这部分题目很难,而且很不容易理解,目前我的题目做了一半,凭着之前对于「动态规划」的理解和最近做的题目做 ...

  7. 导弹拦截问题(DP+贪心)

    1. 拦截导弹(Noip1999) 某国为了防御敌国的导弹袭击,发展出一种导弹拦截系统.但是这种导弹拦截系统有一个缺陷:虽然它的第一发炮弹能够到达任意的高度,但是以后每一发炮弹都不能高于前一发的高度. ...

  8. POJ-1456 Supermarket(贪心,并查集优化)

    Supermarket Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 10725 Accepted: 4688 Descript ...

  9. 【NOIP模拟赛】就 反悔贪心

    biubiu~~~ 这道题,考场上上来就dp然后发现怎么优化也不行.............最后发现是贪心............. 正解:带反悔的贪心,原理是,假设我们现在得到了取i个的最优解那么我 ...

随机推荐

  1. Linux: 如何分割文件,不再被 4G 大小限制了

    单文件 4G 限制 FAT32 4G 限制 百度网盘超出 4G 限制 单文件分割与合并 单文件,如:archive.tar.gz 分割 split -b 3000M -d -a 1 archive.t ...

  2. struts 通配符的使用

    使用通配符可以将配置量降到最低,十分方便 新建一个javaweb项目 在项目中加入Struts.xml( 选中项目右键MyEclipse-->project facets-->Struts ...

  3. 使用WPF实现的 喜马拉雅FM 资源下载工具

    因为喜马拉雅pc网站上没有提供下载功能,之前有个同事问我有没有办法将资源下载到本地,当然通过浏览器F12也能找到下载地址,但挺麻烦.正好最近想学wpf,周末在家也没事,于是对着百度撸了下代码.当然只能 ...

  4. 58同城Java面试

    总结这一次面试失败的不冤 很多知识,都是了解.知道,而没有做到明白与彻底的弄懂 差距还是比较大的 以后要多来写总结,提升自己,争取早日被认可 说说今天面试的主要内容和问题吧 希望大家集思广益 面试职位 ...

  5. JCreator配置的Java学习环境

    绕不开的配置,很多东西需要它,论精力现在还折腾不来,可总不至于去见马克思的那一天才来啊,该来的就该来不躲避(Py及其Android.BigData都绕不开,总是触动着我)!不想那些庞大耗内存的Ecli ...

  6. Excel只想显示一部分日期,怎样把其余部分隐藏起来?

      问题:只想显示一部分日期,怎样把其余部分隐藏起来? 方法:分列 Step1:选中需要修改的单元格——数据——分列. Step2:固定宽度——点击下一步. Step3:在建立分列处单击鼠标(若想取消 ...

  7. 用turtle画蛇

    import turtle def drawSnake(rad,angle,len,nackrad): for i in range(len): turtle.circle(rad,angle) #画 ...

  8. MySQL数据表中有自增长主键时如何插入数据

    原文链接:https://blog.csdn.net/RuobaiMEN/article/details/79794199 MySQL数据库表中有自增主键ID,当用SQL插入语句中插入语句带有ID列值 ...

  9. Spring Cloud 系列之 Dubbo RPC 通信

    Dubbo 介绍 官网:http://dubbo.apache.org/zh-cn/ Github:https://github.com/apache/dubbo 2018 年 2 月 15 日,阿里 ...

  10. 【Laravel】 常用的artisan命令

    全局篇 查看artisan命令php artisanphp artisan list 查看某个帮助命令php artisan help make:model 查看laravel版本php artisa ...