BZOJ1812: [Ioi2005]riv

1812: [Ioi2005]riv

Time Limit: 10 Sec  Memory Limit: 64 MB
Submit: 523  Solved: 309
[Submit][Status][Discuss]

Description


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

Input

第一行 包括两个数 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村子下游最近的村子(或bytetown)(0<=vi<=n)
di——vi到i的距离(km)。(1<=di<=10000)
保证每年所有的木料流到bytetown的运费不超过2000,000,000分
50%的数据中n不超过20。

Output

输出最小花费,精确到分。

Sample Input

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

Sample Output

4

HINT

Source

【题解】

先左耳子右兄弟转二叉树,方便转移

f[i][j][k]表示在原树中i和i的兄弟节点所在的子树(相当于转换后i及其子树中),在原树中离i最近的父亲点为j,

放置k个工厂的最小距离

转移:

f[i][j][k] = min{

选       f[l[i]][i][a] + f[r[i]][j][k - a - 1]

不选 d[l[i]][j][a] + f[r[i]][j][k - a] + dist[i, j]

}

 1 #include <iostream>
 2 #include <cstdio>
 3 #include <cstdlib>
 4 #include <cstring>
 5 #include <cmath>
 6 #include <algorithm>
 7 #define min(a, b) ((a) < (b) ? (a) : (b))
 8 #define max(a, b) ((a) > (b) ? (a) : (b))
 9
10 inline void read(int &x)
11 {
12     x = 0;char ch = getchar(), c = ch;
13     while(ch < ‘0‘ || ch > ‘9‘)c = ch, ch = getchar();
14     while(ch <= ‘9‘ && ch >= ‘0‘)x = x * 10 + ch - ‘0‘, ch = getchar();
15     if(c == ‘-‘)x = -x;
16 }
17
18 const int MAXN = 100 + 10;
19 const int MAXK = 50 + 10;
20 int dp[MAXN][MAXN][MAXK],n,m,cost[MAXN],fa[MAXN],dist[MAXN];
21 int l[MAXN], r[MAXN], flag;
22
23 void dfs(int i)
24 {
25     if(!i && flag)return;
26     flag = 1;
27     dfs(l[i]);
28     dfs(r[i]);
29     int len = dist[i];
30     for(register int j = fa[i];j != -1;j = fa[j])
31     {
32         for(register int k = 0;k <= m;++ k)
33         {
34             for(register int a = 0;a <= k;++ a)
35             {
36                 if(k - a - 1 >= 0)
37                     dp[i][j][k] = min(dp[i][j][k], dp[l[i]][i][a] + dp[r[i]][j][k - a - 1]);
38                 if(k - a >= 0)
39                     dp[i][j][k] = min(dp[i][j][k], dp[l[i]][j][a] + dp[r[i]][j][k - a] + len * cost[i]);
40             }
41         }
42         len += dist[j];
43     }
44 }
45
46 int main()
47 {
48     read(n), read(m);
49     for(register int i = 1;i <= n;++ i)
50     {
51         read(cost[i]), read(fa[i]),read(dist[i]);
52         r[i] = l[fa[i]];
53         l[fa[i]] = i;
54     }
55     memset(dp, 0x3f, sizeof(dp));
56     memset(dp[0], 0, sizeof(dp[0]));
57     fa[0] = -1;
58     dfs(0);
59     printf("%d", dp[l[0]][0][m]);
60     return 0;
61 }

BZOJ1812

时间: 2024-10-25 08:05:30

BZOJ1812: [Ioi2005]riv的相关文章

bzoj1812 [IOI2005]riv河流

题目链接 problem 给出一棵树,每个点有点权,每条边有边权.0号点为根,每个点的代价是这个点的点权\(\times\)该点到根路径上的边权和. 现在可以选择最多K个点.使得每个点的代价变为:这个点的点权\(\times\)改点到最近的被选中的一个祖先的边权和. 问所有点的代价和最小为多少. solution 用\(g[i][j]\)表示以i为根的子树,强制选i,最大的贡献(这里的贡献是指比什么也不选所减少的代价.) 最终答案肯定就是初始代价-g[0][k] 考虑怎么维护出\(g\).用\(

1812: [Ioi2005]riv

1812: [Ioi2005]riv Time Limit: 10 Sec Memory Limit: 64 MB Submit: 635 Solved: 388 [Submit][Status][Discuss] Description 几乎整个Byteland王国都被森林和河流所覆盖.小点的河汇聚到一起,形成了稍大点的河.就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海.这条大河的入海口处有一个村庄--名叫Bytetown 在Byteland国,有n个伐木的村庄,这些村庄都座

【BZOJ1812】riv(多叉树转二叉树,树形DP)

题意:给定一棵树,每个点有权值,每条边有边权(单向边).你可以选取K个黑点,使得从每个点移动到距离他最近的黑点的花费(距离*点权)的总和最小. n<=100 k<=50 w[i],a[i]<=10000 思路:见IOI2005龙凡解题报告 又是一道从父亲到儿子的树形DP 为什么要多叉转二叉?因为假设点U被选,这个被选点只会对U自己的儿子有影响,对U的兄弟并没有影响 dp[i,j,k]表示以i为根的子树,建j个节点,离i最近的被选点是k时的最小总和 \[ dp[i,j,k]=min\beg

BZOJ1812 [IOI2005]river

传送门: 很常规的一道树规,转为左儿子右兄弟. 然后f[node][anc][K]表示在node节点上,最近的有贡献祖先在anc上,在node的儿子和兄弟上有k个有贡献节点的最优值. 然后得出以下转移方程. f[node][anc][K]=min{f[son[node]][anc][k]+f[bro[node]][anc][K-k]}+Value[node]*(dis[node]-dis[anc]); 无贡献 f[node][anc][K]=min{f[son[node]][node][k]+f

[IOI2005]Riv 河流

题目描述 几乎整个Byteland 王国都被森林和河流所覆盖.小点的河汇聚到一起,形成了稍大点的河.就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海.这条大河的入海口处有一个村庄--Bytetown.在Byteland国,有n个伐木的村庄,这些村庄都座落在河边.目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料.木料被砍下后,顺着河流而被运到Bytetown的伐木场.Byteland 的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场.这k个伐木场将被

带权二分

带权二分 一种二分答案的套路,又叫做DP凸优化,wqs二分. 用来解决一类题目,要求某个要求出现K次,并且,可以很显然的发现,在改变相应权值的时候,对应出现的次数具有单调性.而且很显然,这种题一般满足一定的要求.而且一般权值为整数二分就可以,但是有的题需要实数二分...而且,边界条件通常很麻烦,调起来想摔电脑. 例题时间: BZOJ2654: tree 题目大意:给你一个图,里面有白色边和黑色边,问恰好有k条边白色边的最小生成树 直接贪心法肯定是错误的,因此,我们考虑带权二分. 给定一个选择白色

YCB 的暑期计划

前言 YCB现在很弱(TAT) 暑假有一个月,赶快狂补一下. 大概的计划如下: 首先前期会以数据结构为主,毕竟代码能力太弱,涉及内容:线段树分治.二进制分组.KD-Tree. 等数据结构做到没有智商的时候加入一波数论,内容为 杜教筛.min_25筛. 然后中途小清新一下,做一些 组合博弈与构造题. 接着继续练代码能力,顺便学一些神奇的暴力:启发式合并.dsu on tree . 然后图论也忘的差不多了,就回过头去学点新东西,大概会有spfa判负环.0/1分数规划.差分约束. 估计这个时候也没有什

bzoj1812 riv(树形背包)

dp[i][j][k]表枚举到第i个节点,以该结点为根的子树中建了k个伐木场,距离i最近的伐木场是j的最小距离 有一些细节... 代码: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int n,m,cnt; int head[205]; int fa[205]; int val[205]; int dis[205][205]; int dp[205][205][5

[bzoj1812][IOI2006]riv_多叉树转二叉树_树形dp

riv bzoj-1812 IOI-2006 题目大意:给定一棵n个点树,要求在上面建立k个收集站.点有点权,边有边权,整棵树的代价是每个点的点权乘以它和它的最近的祖先收集站的距离积的和. 注释:$1\le n \le 100$,$1\le k \le 50$. 想法:显然,这是一道树形dp题.状态也非常容易... ...只不过,我们好像要枚举子集... 所以,我们这里有一个黑科技:多叉树转二叉树. 我们先把它转成二叉树,然后再进行转移即可. 状态:dp[i][j][k]表示以i为根的子树中选出