【题目描述】
有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。问收益最大值是多少。
【输入格式】
第一行两个整数N,K。
接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。输入保证所有点之间是联通的。
【输出格式】
输出一个正整数,表示收益的最大值。
【输入样例1】
3 1
1 2 1
1 3 2
【输出样例1】
3
【输入样例2】
5 2
1 2 3
1 5 1
2 3 1
2 4 2
【输出样例2】
17
【样例解释】
在第二个样例中,将点1,2染黑就能获得最大收益。
【数据范围】
对于30%的数据,N<=20
对于50%的数据,N<=100
对于100%的数据,N<=2000,0<=K<=N。

题解

很显然是个树dp,然后问题来了,怎么设计状态,根据经验我们可以设计出$dp[i][j]$表示以$i$为根的子树中染了$j$个黑点的贡献,但是这里所说的贡献是对整体还是只考虑局部呢,答案是对整体的贡献,因为很显然这个题目中满足局部最优并不一定就满足整体最优,这样状态定义就结束了,我们在来考虑转移,我们设当前枚举的根节点为$x$,我们再来枚举他的子节点$y$,发现无法直接通过子节点转移到父节点,我们再考虑,是什么连接子节点和父节点,是边,那我们就可以通过边的贡献来转移,那么每条边的贡献就是边权×子树中黑点数×子树外黑点数+边权×子树中白点数×子树外白点数。这样就可以愉快的转移了

$dp[x][j+m]=\max{(dp[y][m]+dp[x][j]+val)}$

其中j枚举x子树大小,m枚举y子树大小,val就是边的贡献。

然后就是要倒着枚举(其实正着枚举也行,就是麻烦),因为如果单纯的正着枚举,会导致用更新过的来更新,而不是正常的转移,即你要用之前的子树大小和当前子树来更新父节点,但如果不做任何处理的正着枚举就会导致用已经更新到size的值来更新,就会不对。

还有就是转移要放到dfs循环里边,其实和上面一样,就是你只是用前面的size,而不是总的size,具体看代码里的注释吧

还有要注意的一点就是因为这题你把所有黑点和白点互换不会对答案产生影响,所以$k=\min{(k,n-k)}$。

一遍dfs即可。

这样做的复杂度时$O(n^2)$的,简单点说就是因为每个点最多只会和其他点乘一次。

 #include<cstdio>
using namespace std;
const int N=,M=,L=<<|;
//#define int long long
#define rg register int
int first[N],nex[M],to[M],edge[M],v[N],size[N],tot,n,k;long long dp[N][N];
char buf[L],*S,*T;
#define getchar() ((S==T&&(T=(S=buf)+fread(buf,1,L,stdin),S==T))?EOF:*S++)
inline int read(){
rg ss=;register char bb=getchar();
while(bb<||bb>)bb=getchar();
while(bb>=&&bb<=)ss=(ss<<)+(ss<<)+(bb^),bb=getchar();
return ss;
}
inline void add(rg a,rg b,rg c){
to[++tot]=b,edge[tot]=c,nex[tot]=first[a],first[a]=tot;
}
inline int max(rg a,rg b){return a>b?a:b;}
inline int min(rg a,rg b){return a<b?a:b;}
inline long long Max(long long a,long long b){return a<b?b:a;}
void dfs(int x){
int y;
size[x]=;v[x]=;
for(int i=first[x];i;i=nex[i]){
if(v[y=to[i]]) continue;
dfs(y);
rg z=edge[i];
rg qq=min(size[x],k),pp=min(size[y],k);
//倒序枚举
for(rg j=qq;j>=;--j)//这块要放到里面,原因见blog
for(rg l=pp;l>=;--l){
long long del=1ll*z*1ll*l*1ll*(k-l)+1ll*z*1ll*(size[y]-l)*1ll*(n-k-(size[y]-l));
dp[x][j+l]=Max(dp[x][j+l],dp[y][l]+dp[x][j]+del);
}
size[x]+=size[y];
}
}
signed main(){
n=read(),k=read();
k=min(k,n-k);
for(rg i=;i<n;++i){
rg x=read(),y=read(),z=read();
add(x,y,z);
add(y,x,z);
}
dfs();
printf("%lld",dp[][k]);
}

[HAOI2015][bzoj 4033]树上染色(树dp+复杂度分析)的更多相关文章

  1. [BZOJ 4033] 树上染色

    Link: BZOJ 4033 传送门 Solution: 此题用到了计算贡献的方法, 将 多条路径的路径和  $->$ $\sum_{i=1}^{n-1} w[i]*cnt[i]$ 这样我们由 ...

  2. bzoj 4033 树上染色 - 树形动态规划

    有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑 色,并将其他的N-K个点染成白色.将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的 ...

  3. 洛谷 P3177 [HAOI2015]树上染色 树形DP

    洛谷 P3177 [HAOI2015]树上染色 树形DP 题目描述 有一棵点数为 \(n\) 的树,树边有边权.给你一个在 \(0 \sim n\)之内的正整数 \(k\) ,你要在这棵树中选择 \( ...

  4. bzoj 4033: [HAOI2015]树上染色 [树形DP]

    4033: [HAOI2015]树上染色 我写的可是\(O(n^2)\)的树形背包! 注意j倒着枚举,而k要正着枚举,因为k可能从0开始,会使用自己更新一次 #include <iostream ...

  5. [HAOI2015]树上染色 树状背包 dp

    #4033. [HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并 将其他的N-K个点染成白 ...

  6. [BZOJ4033][HAOI2015]树上染色(树形DP)

    4033: [HAOI2015]树上染色 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 2437  Solved: 1034[Submit][Stat ...

  7. 【BZOJ4033】[HAOI2015]树上染色 树形DP

    [BZOJ4033][HAOI2015]树上染色 Description 有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染 ...

  8. 【HAOI2015】树上染色—树形dp

    [HAOI2015]树上染色 [题目描述]有一棵点数为N的树,树边有边权.给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色.将所有点染色后,你会获得 ...

  9. bzoj 3572世界树 虚树+dp

    题目大意: 给一棵树,每次给出一些关键点,对于树上每个点,被离它最近的关键点(距离相同被标号最小的)控制 求每个关键点控制多少个点 分析: 虚树+dp dp过程如下: 第一次dp,递归求出每个点子树中 ...

随机推荐

  1. ArcGIS Server SOE地图服务重启特别卡

    ArcGIS Server 服务器端扩展,SOE代码调试时,需要经常重新编译.替换地图服务中的扩展, 由于未知问题,本地开发环境包含SOE的地图服务,每次重启都需要耗费相当长的时间,大体上20多分钟, ...

  2. LOJ3123 CTS2019 重复 KMP自动机、DP、多项式求逆

    传送门 CTS的计数题更完辣(撒花 Orz zx2003,下面的内容在上面的博客基础上进行一定的补充. 考虑计算无限循环之后不存在子串比\(s\)字典序小的串的个数.先对串\(s\)建立KMP自动机, ...

  3. go ---fmt

    //main package main import ( "fmt" "os" ) type Data struct { } func (self Data) ...

  4. C# ——Parallel类

    一.Parallel类 Parallel类提供了数据和任务的并行性: 二.Paraller.For() Paraller.For()方法类似于C#的for循环语句,也是多次执行一个任务.使用Paral ...

  5. Unable to instantiate org.apache.hadoop.hive.ql.metadata.SessionHiveMetaStoreClient报错,问题排查

    背景 最近在整合pyspark与hive,新安装spark-2.3.3以客户端的方式访问hive数据,运行方式使用spark on yarn,但是在配置spark读取hive数据的时候,这里直接把hi ...

  6. Euraka适合初学者的简单小demo

    1. 创建父工程:父工程的的打包形式该为pom,删除其余无关的文件 修改父工程的pom文件内容如下: <?xml version="1.0" encoding="U ...

  7. Node笔记(新手入门必看)

    . 初识Node.js 1.1 Node.js是什么 Node.js® is a JavaScript runtime built on Chrome's V8 JavaScript engine. ...

  8. 各种GAN的学习和总结

    GAN: https://www.cnblogs.com/kk17/p/10046884.html WGAN: https://www.cnblogs.com/Allen-rg/p/10305125. ...

  9. git小结-ms

    目录 1.git是什么 2.git怎么工作的 3.git常用命令 4.git提效工具 5.git的技术用语 1.git是什么 git是开源的分布式的版本控制系统,可以有效.高速地处理的项目版本管理.g ...

  10. Nacos Docker集群部署

    参考文档:https://nacos.io/zh-cn/docs/quick-start-docker.html 1.从git上下载nacos-docker项目,本地目录为/docksoft/naco ...