题目描述

几乎整个Byteland 王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——Bytetown。
在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland 的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在 运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。
注:所有的河流都不会分叉,形成一棵树,根结点是Bytetown。
国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一吨木料每千米1分钱。
编一个程序:
1.从文件读入村子的个数,另外要建设的伐木场的数目,每年每个村子产的木料的块数以及河流的描述。
2.计算最小的运费并输出。

输入

输入格式 Input Format  
     第一行包括两个数n(2<=n<=100),k(1<=k<=50,且k<=n)。n为村庄数,k为要建的伐木场的数目。除了Bytetown 外,每个村子依次被命名为 1,2,3……n,Bytetown被命名为0。
接下来n行,每行3个整数:
wi——每年 i 村子产的木料的块数。(0<=wi<=10000) 
vi——离 i 村子下游最近的村子。(即 i 村子的父结点)(0<=vi<=n) 
di——vi 到 i 的距离(千米)。(1<=di<=10000) 
保证每年所有的木料流到bytetown 的运费不超过2000,000,000分 
50%的数据中n不超过20。

输出

输出最小花费,精确到分

样例输入

4 2
1 0 1
1 1 10
10 2 5
1 2 3

样例输出

4

一道dp好题,希望借此稍微对dp算法的构思进行下探究

第一步:化简问题

化简问题既是对包装好的复杂题面的化简,也是对题目性质的初步探究。这一步非常关键,我在第一次做的时候这里就出现了问题……

当时化简成了“先统计经过每条路的数量,再把每条路的贡献加到一起”,这个化简得错误就在于没有注意到我们可以把木材集中与他的生产点上考虑

这样去考虑就无形的把本来是一个点上的问题拆成了许多条边上的问题。。。

  • 这也体现了当一个思路不通时,要及时的改变思路,不要硬钻牛角尖

正确的化简姿势:每个节点有一个权值,然后在树上选择K个点,使得从节点到最近一个选择的节点的距离乘以点权最小。

第二步:设计状态

我觉得一个好的dp状态应该具备以下几点要求

  1. 能全面的表达当前形势。能够不产生歧义,且对状态的转移产生影响的所有变量都有涵盖
  2. 没有后效性。dp状态拆分出来的子问题应该能够在自己内部单独解决,而不需要考虑问题之间的影响

针对这道题,一个很自然的思路是设 f(i,k),表示以i为节点的子树中,建了k个伐木场,里面每个节点的木材产生贡献的总和的最小值

但我们发现一个问题,这个状态并不唯一,我们发现这个值受离子树最近的伐木场影响

所以拓充状态为 f(i,j,k) j表示j为i及其祖先中离i最近的伐木场,k个伐木场中不算这个

这样发现状态的不足对其进行补充是需要加强的一点,有的时候也需要推翻重新设计状态

第三步:转移

这一步就因题而异了,要强调一点的就是要灵活运用数据结构,不要被类似题限制住了

首先对i的儿子们来说相当于是一个一个子树的接,因此考虑使用背包dp的形式处理

f(i,j,k)=min{f(i,j,k-x)+f(v,j,x)};

最后再 f(i,j,k)+=s[i]*(dep[i]-dep[j]) s[i]是这个点的权值

然后当他的祖先们再用的侯,如果i==j的话就不对了,所以所有的f(i,j,k)都要被更新一发f(i,i,k-1)(在计算的时候没有考虑自己这个位置上的消耗,所以-1)

来看看代码吧~:

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 int n,K,size,vi,di,etop;
 5 int sum[501],nxt[1001],to[1001],w[1001],h[501],sta[1001],dep[1001];
 6 long long f[111][111][51];
 7 void add(int x,int y,int dis){
 8     etop++;nxt[etop]=h[x];h[x]=etop;to[etop]=y;w[etop]=dis;
 9 }
10 void dfs(int i){
11     sta[++size]=i;
12     for(int t=h[i];t;t=nxt[t]){
13         int v=to[t];
14         dep[v]=dep[i]+w[t];
15         dfs(v);
16         for(int j=1;j<=size;j++)
17             for(int k=K;k>=0;k--){
18                 f[i][sta[j]][k]+=f[v][sta[j]][0];
19                 for(int x=0;x<=k;x++)
20                     f[i][sta[j]][k]=min(f[i][sta[j]][k],f[i][sta[j]][k-x]+f[v][sta[j]][x]);
21             }
22     }
23     for(int j=1;j<=size;j++)
24         for(int k=0;k<=K;k++){
25             if(k>=1)
26                 f[i][sta[j]][k]=min(f[i][sta[j]][k]+sum[i]*(dep[i]-dep[sta[j]]),f[i][i][k-1]);
27             else
28                 f[i][sta[j]][k]+=sum[i]*(dep[i]-dep[sta[j]]);
29         }
30     size--;
31 }
32 int main(){
33     scanf("%d%d",&n,&K);
34     for(int i=1;i<=n;i++){
35         scanf("%d%d%d",&sum[i],&vi,&di);
36         add(vi,i,di);
37     }
38     dfs(0);
39     printf("%d\n",f[0][0][K]);
40     return 0;
41 }

View Code

这里在转移时利用了栈

双倍经验还有:https://www.luogu.org/problemnew/show/CF1082F

转载于:https://www.cnblogs.com/2017SSY/p/10217173.html

[IOI2005]Riv 河流相关推荐

  1. 『树形DP』[IOI2005]Riv 河流

    题目描述 题解 我们设f[x][j][k]f[x][j][k]f[x][j][k]表示运输完了以xxx为根的子树,iii的祖先jjj建立了伐木场,建立了kkk个伐木场的最小运输代价.由于题目中说明了0 ...

  2. [LUOGU] P3354 [IOI2005]Riv 河流

    题目描述 几乎整个Byteland王国都被森林和河流所覆盖.小点的河汇聚到一起,形成了稍大点的河.就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海.这条大河的入海口处有一个村庄--名叫 ...

  3. [IOI2005]Riv河流

    题目链接:洛谷,BZOJ 前置知识:莫得 题解 直接考虑dp.首先想法是设状态 \(dp[u][i]\) 表示u的子树内建 \(i\) 个伐木场且子树内木头都运到某个伐木场的最小花费.发现这样的状态是 ...

  4. 洛谷 P3354 [IOI2005]Riv 河流【树形dp】

    ... 题目: 题意: 分析: 代码: 题目: 传送门 题意: 给出一棵有nnn个节点的树,每条边有一个距离,每个点有一个权值 我们需要选出除根节点以外的kkk个节点,每个点的答案为该点的点权向上直到 ...

  5. P3354 [IOI2005]Riv 河流

    树形dp,设f[i][j][k]表示第i个点的子树中选择j个点作为伐木场,而且k是建了伐木场的最浅的i的祖先的情况下,最小的收益. 这种题还要练一下,咕咕 然后转移可以n4方做. // luogu-j ...

  6. Luogu P3354 [IOI2005]Riv河流 题解———再加一维!再加一维!

    Description n≤100,k≤min(n,50)n≤100,k≤min(n,50)n≤100,k≤min(n,50). Solution 考虑树形dpdpdp. 状态设计为dpi,jdp_{ ...

  7. 洛谷P3354 [IOI2005]Riv 河流——“承诺”DP

    题目:https://www.luogu.org/problemnew/show/P3354 状态中要记录一个"承诺",只需相同承诺之间相互转移即可: 然后就是树形DP的套路了. ...

  8. BZOJ.1812.[IOI2005]Riv 河流(树形背包)

    BZOJ 洛谷 这个数据范围..考虑暴力一些把各种信息都记下来.不妨直接令\(f[i][j][k][0/1]\)表示当前为点\(i\),离\(i\)最近的建了伐木场的\(i\)的祖先为\(j\),\( ...

  9. 【bzoj 1812】[Ioi2005]riv(树形dp)

    1812: [Ioi2005]riv Time Limit: 10 Sec  Memory Limit: 64 MB Submit: 433  Solved: 246 [Submit][Status] ...

最新文章

  1. React Native小白入门学习路径——五
  2. 每天一道LeetCode-----判断某棵树是否是二叉搜索树
  3. php json -gt;访问,【转】Php+ajax+jsonp解决ajax跨域问题
  4. php 构造骚扰短信发送机(仅供学习与参考,请勿用于非法用途)
  5. 杂文笔记《“去QE”时代下,QE如何破茧重生》
  6. python第三方模块下载方法(最详最细)
  7. 设置电子围栏 高德地图_高德地图 自动生成电子围栏
  8. JavaScript在表格中实现九九乘法表
  9. 【叶子函数分享五十四】汉字转拼音函数
  10. 环境混合物总体效应:加权分位数和回归(WQS)
  11. Linux开发板开机自动连接WiFi,IMX6UL(讯为开发板)。
  12. 用淘汰的笔记本搭建服务器,使用神卓互联来做内网穿透不要太香
  13. PTA-c语言 新胖子公式
  14. Android 开发艺术探索笔记(17),android开发艺术探索
  15. 画个板子玩一玩STM32F030F4P6,也许是最便宜的32bit MCU
  16. 使用internal(com.android.internal)和hidden(@hide)APIs
  17. js 对一个字段去重_js面试
  18. Android检测系统的摄像头是否可用
  19. 百度地图  全景控件
  20. python---pandas基础知识(学习笔记)

热门文章

  1. java part part,java泛型指导手册(part1),指导手册part1
  2. 凭据分配没有加密oracle_远程连接身份验证错误,又找不到加密Oracle修正
  3. 文档转成html在线预览,java poi Word文档转为HTML文件 实现在线预览功能
  4. mysql8.0连接错误_MySql 8.0连接失败
  5. java 正则判断二进制_regex – 正则表达式,用于定义一些二进制序列
  6. python 指针_C++的动态内存:C++的指针
  7. python统计英文单词个数_python统计英文文本中的回文单词数
  8. mooc java_中国大学moocJava程序设计答案大全
  9. 软件维护复杂度的因素
  10. java常用的网关有哪几种_拼多多java开发一面、二面合并面经