题目大意:

给定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. c#基础系列3---深入理解ref 和out

    "大菜":源于自己刚踏入猿途混沌时起,自我感觉不是一般的菜,因而得名"大菜",于自身共勉. 扩展阅读 c#基础系列1---深入理解 值类型和引用类型 c#基础系 ...

  2. Ceph分布式存储集群-硬件选择

    在规划Ceph分布式存储集群环境的时候,对硬件的选择很重要,这关乎整个Ceph集群的性能,下面梳理到一些硬件的选择标准,可供参考: 1)CPU选择Ceph metadata server会动态的重新分 ...

  3. VS2015安装及单元测试

    今天跟大家分享一下我的VS2015的安装过程以及对单元测试的操作步骤.VS2015是一款非常好用的编程软件,内容很多很广泛,是深受欢迎的一款软件,较之于VC++6.0有着一些好处,对VC6.0++来说 ...

  4. 软件项目第一次Sprint总结

    成果评分表: 组名 分数 原因 9-652 6 界面和谐生动,可运行,在目前阶段可时间基本操作 hzsy -2 代码下载,但实现安卓和相机调用 JYJe族 -1 实现安卓界面,完成一项功能,做得少 结 ...

  5. <<浪潮之巅>>阅读笔记三

    纵看世界,横看国内.我们国内也有很多很优秀的企业正在走向或者已经处于浪潮之巅.阿里巴巴.腾讯和百度这三巨头应该是我们计算机行业的龙头.但是 不得不说,在创新方面我们做的并不多,这是值得每一个从事计算机 ...

  6. C++课程学习建议

    从C到C++,学院都采用了机房授课模式,也在探索更为高效的实践与理论融合的教学方法,对于课程学习来说,仍有以下建议: 1.多看书.看书是理解基本概念的必备手段.也是学习的根本.应将课前预习.课后复习联 ...

  7. 阅读<构建之法>13、14、15、16、17章

    13章 这么多测试为什么不能整理出一个包括所有功能的测试呢?看着那么多测试都感觉奇怪了. 14章 怎样才能体现一个测试人员的工作价值呢?这样的判断又是否会太独断了? 15章 在时间上,会不会因不同功能 ...

  8. Docker(二十)-Docker容器CPU、memory资源限制

    背景 在使用 docker 运行容器时,默认的情况下,docker没有对容器进行硬件资源的限制,当一台主机上运行几百个容器,这些容器虽然互相隔离,但是底层却使用着相同的 CPU.内存和磁盘资源.如果不 ...

  9. Jquery ajax load(),get(),post()

    //load()用来加载html文档中的代码片段,添加到指定元素内部 //如果只加部分选定的元素可以.load("url 选择器") <!DOCTYPE html>&l ...

  10. codeforces279B

    Books CodeForces - 279B When Valera has got some free time, he goes to the library to read some book ...