【题目描述】
有一棵点数为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. 【题解】Luogu P4910 帕秋莉的手环

    原题传送门 "连续的两个中至少有1个金的"珂以理解为"不能有两个木相连" 我们考虑一个一个将元素加入手环 设f\([i][0/1]\)表示长度为\(i\)手环末 ...

  2. 雪花算法,生成分布式唯一ID

    2.3 基于算法实现 [转载] 这里介绍下Twitter的Snowflake算法——snowflake,它把时间戳,工作机器id,序列号组合在一起,以保证在分布式系统中唯一性和自增性. snowfla ...

  3. @PostConstruct使用总结

    https://blog.csdn.net/qq_37636695/article/details/84791468 https://www.jianshu.com/p/aba99a49a459 @P ...

  4. jdbcUrl is required with driverClassName

    https://blog.csdn.net/newbie_907486852/article/details/81391525 springboot2.0配置多数据源: spring.datasour ...

  5. 《.NETer提高效率——环境部署》

    初衷 兵马未动,粮草先行. 电脑坏了or换工作等需要重装系统. 开发运维一把梭. 与时俱进. 记忆力差,需要文字记录. 因为懒... 目的 通过学习 Linux+docker+kubernetes+C ...

  6. 从 SimpleIntegerProperty 看 Java属性绑定(property binding) 与 观察者模式(Observable)

    //TODO:ExpressionHelper .bindBidirectional双向绑定.以及IntegerExpression的一系列算术方法和返回的IntegerBinding暂未详细解析(比 ...

  7. c# 日期和时间System.DateTime

  8. 为群晖加把锁:使用ssh密钥保障数据安全

    对每一个使用群晖nas的人而言,能保证群晖里保存的数据不被未经授权的人访问下载甚至破坏可能是最重要的事情.但数据只要上网,就免不了担心密码被破解,群晖被侵入.现在网络上,要破解密码可能是最简单不过的事 ...

  9. Virtualization and Performance: Understanding VM Exits

    翻译自:Virtualization and Performance: Understanding VM Exits 出于对特定指令 或 特定事件(eg.  page fault)的响应而导致的VM ...

  10. AD如何改变PCB文件的黑色背景

    第一步:打开AD软件,新建一个PCB文件.   2 第二步:在黑色区域随便画一个封闭的多边形——注意一定要是封闭的!   3 第三步:点击“Ctrl + A”快捷键将PCB整个文件选中.   4 第四 ...