题目大意:

给定n个点的有根树,每条边有边权,每个点有点权w,

你要在k个点上建立伐木场,对于每个没有建伐木场的点x,令与它最近的祖先、有伐木场的点,为y,你需要支付dis(x,y)*w[x]的代价。

选择合适的位置建伐木场,最小化总代价。

n<=100

分析:

f[i][j][k]表示, 以i为根的子树中,离其最近的祖先为j,加上这个点的子树共建了k个伐木场。

树形背包,每个点选择建伐木场,或者不选择建。

注意,无论如何,在x子树y回溯后,是可以在子树根节点y造一个伐木场的。这种情况不要漏掉。

因为0处一定有一个伐木场,所以我们先假设它没有这个伐木场,将k++即可。最后答案就是f[0][0][k] 第二维是0,表示0号点最近的伐木场就是它自己,也就是强制让0点建了一个场。

具体做法:

开始f都是inf

进入每一个节点x,都进行初始化。f[x][x][1~k]=0,f[x][x][1]=0,f[x][ancestors][0]=dis*w[x]

进行树形dp的时候,回溯了y儿子,进行背包前,先新建一个数组g,赋值为inf,否则需要f赋值的时候,f却有可能已经变了。

再把g赋值给f。

背包的时候,分类讨论,一个是在x点建场,还有就是不建场,需要枚举一个最近的祖先。这里,我用的是fa[]数组,不断找父亲,以及disf[]到父亲节点的边的长度。

详见代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=+;
const int K=;
const ll inf=+;
struct node{
int nxt,to;
ll val;
}bian[*N];
int hd[N],cnt;
ll w[N];
int n,k;
ll f[N][N][K];
int fa[N];
ll disf[N];
bool vis[N];
void add(int x,int y,ll z)
{
bian[++cnt].nxt=hd[x];
bian[cnt].to=y;
bian[cnt].val=z;
hd[x]=cnt;
}
void dfs(int x)
{
vis[x]=;
for(int i=;i<=k;i++)
f[x][x][i]=;
ll dis=;
   f[x][x][1]=0;
for(int i=x;i!=;i=fa[i])
{
dis+=disf[i];
f[x][fa[i]][]=dis*w[x];
}// prework for(int i=hd[x];i;i=bian[i].nxt)
{
int y=bian[i].to;
if(!vis[y])//find new son
{
dfs(y);
ll g[N][K];
for(int o=;o<N;o++)
for(int u=;u<K;u++)
g[o][u]=inf;
for(int p=;p<=k;p++)//build one
{
for(int q=;q<p;q++)
{
g[x][p]=min(g[x][p],f[x][x][p-q]+f[y][x][q]);// y's lastest ancestor is x
g[x][p]=min(g[x][p],f[x][x][p-q]+f[y][y][q]);// y's lastest ancestor is itself
}
}
for(int j=x;j!=;j=fa[j])//not
{
for(int p=;p<=k;p++)
{
for(int q=;q<=p;q++)
{
g[fa[j]][p]=min(g[fa[j]][p],f[x][fa[j]][p-q]+f[y][fa[j]][q]);//y's lastest ancestor is fa[j]
g[fa[j]][p]=min(g[fa[j]][p],f[x][fa[j]][p-q]+f[y][y][q]);// y's lastest ancestor is itself
}
}
}
for(int j=x;j!=-;j=fa[j])
{
for(int p=;p<=k;p++)
f[x][j][p]=g[j][p];
}//copy back
}
} }
int main()
{
scanf("%d%d",&n,&k);
k++;//warning!!!
int x,y;
ll z;
for(int i=;i<=n;i++)
{
scanf("%lld%d%lld",&w[i],&y,&z);
fa[i]=y;disf[i]=z;
add(i,y,z);
add(y,i,z);
} fa[]=-;
for(int i=;i<N;i++)
for(int j=;j<N;j++)
for(int o=;o<K;o++)
f[i][j][o]=inf;
dfs();
printf("%lld",f[][][k]);
return ;
}

总结:
1.状态设计值得注意,由于代价和祖先有关,因为这是未来要处理的,不容易直接统计。

所以,就对未来做出承诺,如果在j祖先建伐木场,最小的代价。这里就把这个点运到祖先的代价算上了。

这样,dp到这个祖先的时候,如果决定建造,就可以选择实现承诺。

2.然后,初值都是inf,开始只有f[x][x][1]=0,f[x][ancs][0]=dis*w[x],这就保证了,转移的时候,开始必然有f[x][ancs][0]的贡献。不会漏算。

[IOI2005]River 河流的更多相关文章

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

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

  2. BZOJ1812 [IOI2005]river

    传送门: 很常规的一道树规,转为左儿子右兄弟. 然后$f[node][anc][K]$表示在node节点上,最近的有贡献祖先在anc上,在node的儿子和兄弟上有k个有贡献节点的最优值. 然后得出以下 ...

  3. [Ioi2005]River

    设f[i][j][k]表示i上游最近的一个伐木场为j且在i所在的子树里共建了k个伐木场(不包含在i的)的最小运费和 设v为u的儿子,dist[u]为u到0号点的距离. 则当i>=j时 f[u][ ...

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

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

  5. P3354 [IOI2005]Riv 河流

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

  6. 【[IOI2005]Riv 河流】

    趁魏佬去英语演讲了,赶快%%%%%%%%%%%%%%魏佬 基本上是照着魏佬的代码写的 这其实还是一个树上背包 我们用\(dp[i][j][k]\)表示在以\(i\)为根的子树里,我们修建\(k\)个伐 ...

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

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

  8. [IOI2005]Riv 河流

    https://www.zybuluo.com/ysner/note/1300088 题面 有一棵\(n\)个点的树,现在在上面放\(k\)个标记,使得每个点的权值乘上自己到最近的标记祖先的距离的和最 ...

  9. bzoj1812 [IOI2005]riv河流

    题目链接 problem 给出一棵树,每个点有点权,每条边有边权.0号点为根,每个点的代价是这个点的点权\(\times\)该点到根路径上的边权和. 现在可以选择最多K个点.使得每个点的代价变为:这个 ...

随机推荐

  1. 用JS制作一个信息管理平台(1)

    首先,介绍一些需要用到的基本知识. [JSON] JSON是数据交互中,最常用的一种数据格式. 由于各种语言的语法都不相同,在传递数据时,可以将自己语言中的数组.对象等转换为JSON字符串. 传递之后 ...

  2. Mybatis 中 columnPrefix别名的用法

    1.映射对应的属性,区分他们分别属于哪些类.(sql书写的时候为什么要将前缀加上(别名),是因为便于它去寻找哪个类的前缀是ANNEX_) 2.例:  如下所示当一个collection 定义了一个co ...

  3. 定时备份windows机器上的文件到linux服务器上的操作梳理(rsync)

    由于需要对网络设备做备份,备份文件是放到windows机器上的.现在需要将备份数据同步到linux备份机器上,想到的方案有三种: 1)将windows的备份目录共享出来,然后在linux服务器上进行挂 ...

  4. 索引节点(inode)爆满问题处理

    关于磁盘空间中索引节点爆满的问题还是挺多的,借此跟大家分享几个情况: 情况一 在公司一台配置较低的Linux服务器(内存.硬盘比较小)的/data分区内创建文件时,系统提示磁盘空间不足,用df -h命 ...

  5. oracle数据恢复方法

    https://www.cnblogs.com/hqbhonker/p/3977200.html

  6. 个人项目junit4测试

    一.题目简介 用java编写一个程序,模拟ATM柜员机. 二.源码的github链接 www.github.com/liuxianchen/test 三.所设计的模块测试用例.测试结果截图 四  心得 ...

  7. 2017BUAA软工个人作业Week1

    大概的功能已经满足 暂时只能用debug中的exe文件 正在改进... https://github.com/qwellk/project1/tree/product1 PSP2.1 Personal ...

  8. CentOS7 安装 Jenkins

    1. 安装java环境, 自己的虚拟机里面前期已经安装好了 检查一下: [root@centos74 ~]# java -versionopenjdk version "1.8.0_131& ...

  9. html 背景

    用語設置背景的屬性 bgcolor設置背景顏色.可以使用名字.16進制和rgb三種形式的參數: <body bgcolor="#000000"> <body bg ...

  10. python之tkinter使用-二级菜单

    # 菜单功能说明:二级菜单 import tkinter as tk from tkinter import messagebox root = tk.Tk() root.title('菜单选择') ...