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[bro[node]][anc][K-1-k]}                                              有贡献

下面是代码实现:

 1 //BZOJ 1812
 2 //by Cydiater
 3 //2016.9.5
 4 #include <iostream>
 5 #include <cstdio>
 6 #include <cstdlib>
 7 #include <cstring>
 8 #include <string>
 9 #include <algorithm>
10 #include <queue>
11 #include <map>
12 #include <ctime>
13 #include <cmath>
14 #include <iomanip>
15 using namespace std;
16 #define ll long long
17 #define up(i,j,n)        for(int i=j;i<=n;i++)
18 #define down(i,j,n)        for(int i=j;i>=n;i--)
19 const int MAXN=105;
20 const int oo=0x3f3f3f3f;
21 inline int read(){
22     char ch=getchar();int x=0,f=1;
23     while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)f=-1;ch=getchar();}
24     while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();}
25     return x*f;
26 }
27 int N,K,son[MAXN],bro[MAXN],Value[MAXN],dis[MAXN],LINK[MAXN],len=0,fa[MAXN],f[MAXN][MAXN][MAXN],pre_fa[MAXN];
28 struct edge{
29     int y,next,v;
30 }e[MAXN<<1];
31 namespace solution{
32     inline void insert(int x,int y,int v){e[++len].next=LINK[x];LINK[x]=len;e[len].y=y;e[len].v=v;}
33     void dfs(int node){
34         for(int i=LINK[node];i;i=e[i].next){
35             dis[e[i].y]=dis[node]+e[i].v;
36             dfs(e[i].y);
37         }
38     }
39     void init(){
40         N=read();K=read();
41         pre_fa[0]=-1;
42         up(i,1,N){
43             Value[i]=read();int y=read(),v=read();
44             pre_fa[i]=y;
45             insert(y,i,v);
46         }
47         dfs(0);dis[0]=0;
48     }
49     void build(int node,int father){
50         int tmp=LINK[node];son[node]=e[tmp].y;fa[node]=father;
51         if(tmp)build(e[tmp].y,node);node=e[tmp].y;
52         for(int i=e[tmp].next;i;i=e[i].next){
53             bro[node]=e[i].y;build(e[i].y,node);
54             node=e[i].y;
55         }
56     }
57     void TreeDP(int node){
58         if(son[node])TreeDP(son[node]);
59         if(bro[node])TreeDP(bro[node]);
60         int father=pre_fa[node];
61         while(father!=-1){
62             up(lim,0,K)up(k,0,lim){
63                 int tmp=Value[node]*(dis[node]-dis[father]);
64                 if(son[node])tmp+=f[son[node]][father][k];
65                 if(bro[node])tmp+=f[bro[node]][father][lim-k];
66                 f[node][father][lim]=min(f[node][father][lim],tmp);
67             }
68             up(lim,1,K)up(k,1,lim){
69                 int tmp=0;
70                 if(son[node])tmp+=f[son[node]][node][k-1];
71                 if(bro[node])tmp+=f[bro[node]][father][lim-k];
72                 f[node][father][lim]=min(f[node][father][lim],tmp);
73             }
74             father=pre_fa[father];
75         }
76         if(node==0){
77             father=0;
78             up(lim,0,K)up(k,0,lim){
79                 int tmp=0;
80                 if(son[node])tmp+=f[son[node]][father][k];
81                 if(bro[node])tmp+=f[bro[node]][father][lim-k];
82                 f[node][father][lim]=min(f[node][father][lim],tmp);
83             }
84         }
85     }
86     void slove(){
87         build(0,-1);
88         memset(f,0x3f,sizeof(f));
89         TreeDP(0);
90         printf("%d\n",f[0][0][K]);
91     }
92 }
93 int main(){
94     //freopen("input.in","r",stdin);
95     using namespace solution;
96     init();
97     slove();
98     return 0;
99 }

时间: 2024-11-05 20:28:48

BZOJ1812 [IOI2005]river的相关文章

BZOJ1812: [Ioi2005]riv

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

bzoj1812 [IOI2005]riv河流

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

[Ioi2005]River

设f[i][j][k]表示i上游最近的一个伐木场为j且在i所在的子树里共建了k个伐木场(不包含在i的)的最小运费和 设v为u的儿子,dist[u]为u到0号点的距离. 则当i>=j时 f[u][last][i]=max{f[u][last][i-j]+dist[v][last][j]+w[v]*(dist[v]-dist[last])} 即在v不放伐木场 当i>j时 f[u][last][i]=max{f[u][last][i-j-1]+f[v][v][j]} 即在v放伐木场 code: #i

树形动态规划专题

1.OJ1278战略游戏 f[u][0]代表以u为根的子树,u不放时,最少放置节点数. f[u][1]代表以u为根的子树,u放时,最少放置节点数. f[u][0]=Σf[son][1]. f[u][1]=Σmin(f[son][1],f[son][0]). ans=min(f[root][0],f[root][1]). #include<cstdio> #include<iostream> using namespace std; const int maxn=1500; int

带权二分

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

【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

[BZOJ1617][Usaco2008 Mar]River Crossing渡河问题

1617: [Usaco2008 Mar]River Crossing渡河问题 Time Limit: 5 Sec  Memory Limit: 64 MB Submit: 1102  Solved: 801 [Submit][Status][Discuss] Description Farmer John以及他的N(1 <= N <= 2,500)头奶牛打算过一条河,但他们所有的渡河工具,仅仅是一个木筏. 由于奶牛不会划船,在整个渡河过程中,FJ必须始终在木筏上.在这个基础上,木筏上的奶牛数

洛谷—— P2904 [USACO08MAR]跨河River Crossing

https://www.luogu.org/problem/show?pid=2904 题目描述 Farmer John is herding his N cows (1 <= N <= 2,500) across the expanses of his farm when he finds himself blocked by a river. A single raft is available for transportation. FJ knows that he must ride

P2904 [USACO08MAR]跨河River Crossing

P2904 [USACO08MAR]跨河River Crossing 题目描述 Farmer John is herding his N cows (1 <= N <= 2,500) across the expanses of his farm when he finds himself blocked by a river. A single raft is available for transportation. FJ knows that he must ride on the ra