【HAOI2015】树上染色

【题目描述】
有一棵点数为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围绕点来进行,首先你无法定义一种状态,其次你不方便转移

所以我们考虑一条边能产生的贡献

首先一条边能产生的贡献为:

   Wi=dis×((这条边左边的黑点×这条边右边的黑点)+(这条边左边的白点×这条边右边的白点))

我们考虑一对点产生的贡献,这一条边L左侧的黑点要想连接L右侧的黑点,必定经过L,所以L会有贡献

有几对这样的黑点,边L就被经过几次,白点同理,所以得到了上面的方程

我们设f[i][j]表示以i为根节点的子树中染j个黑点的最大收益,

size[x]表示以x为根的子树大小,目标:f[1][k];

设当前搜索到以x为根的子树,设son为x的一个儿子,则:

  $f[x][j]=max(f[x][p]+f[son][j-p]+Wi),$

  $j<=min(size[x],k),p<=min(size[son],k)$

Wi表示x与son所连边产生的贡献,在上面已经解释过了

更新f的时候,如果正着推,就需要把f存到一个临时数组里;循环完后再赋值给f,如果倒着枚举直接更新就好了

当然你还可以减少枚举的数量,即j<=min(size[x],k),p<=min(size[son],k)。

下面给出两份代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MAXN 2005
using namespace std;
ll n,k;
ll fr[MAXN<<],to[MAXN<<],nxt[MAXN<<],pre[MAXN],cnt=,dis[MAXN<<];
void add(ll u,ll v,ll w){
cnt++,fr[cnt]=u,to[cnt]=v,nxt[cnt]=pre[u],pre[u]=cnt,dis[cnt]=w;
}
ll f[MAXN][MAXN],temp[MAXN],size[MAXN];
void dfs(ll x,ll fa){
size[x]=;
for(ll i=pre[x];i;i=nxt[i]){
ll y=to[i];
if(y==fa) continue;
dfs(y,x);
ll num_b1=min(k,size[x]),num_b2=min(k,size[y]),l;
memset(temp,,sizeof(temp));
for(ll j=;j<=num_b1;j++){
for(ll p=;p<=num_b2&&p+j<=k;p++){
l=dis[i]*((k-p)*p+(size[y]-p)*(n-k-size[y]+p));
temp[j+p]=max(temp[j+p],f[x][j]+f[y][p]+l);
}
}
ll m=min(num_b1+num_b2,k);
for(ll j=;j<=m;j++)
f[x][j]=temp[j];
size[x]+=size[y];
}
}
int main(){
scanf("%lld%lld",&n,&k);
for(ll i=,u,v,d;i<n;i++){
scanf("%lld%lld%lld",&u,&v,&d);
add(u,v,d),add(v,u,d);
}
dfs(,);
printf("%lld\n",f[][k]);
return ;
}

正序

#include <iostream>
#include <cstdio>
#include <cstring>
#define ll long long
#define MAXN 2005
using namespace std;
ll n, k;
ll to[MAXN << ], nxt[MAXN << ], pre[MAXN], cnt = , dis[MAXN << ];
void add(ll u, ll v, ll w) { cnt++, to[cnt] = v, nxt[cnt] = pre[u], pre[u] = cnt, dis[cnt] = w; }
ll f[MAXN][MAXN], temp[MAXN][MAXN], size[MAXN];
void dfs(ll x, ll fa) {
size[x] = ;
for (ll i = pre[x]; i; i = nxt[i]) {
ll y = to[i];
if (y == fa)
continue;
dfs(y, x);
ll num_b1 = min(k, size[x]), l;
for (ll j = num_b1; j >= ; j--) {
ll num_b2 = min(k - j, size[y]);
for (ll p = num_b2; p >= ; p--) {
l = dis[i] * ((k - p) * p + (size[y] - p) * (n - k - size[y] + p));
f[x][j + p] = max(f[x][j + p], f[x][j] + f[y][p] + l);
}
}
size[x] += size[y];
}
}
int main() {
scanf("%lld%lld", &n, &k);
for (ll i = , u, v, d; i < n; i++) {
scanf("%lld%lld%lld", &u, &v, &d);
add(u, v, d), add(v, u, d);
}
dfs(, );
printf("%lld\n", f[][k]);
return ;
}

倒序,感谢loj码风优化

【HAOI2015】树上染色—树形dp的更多相关文章

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

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

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

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

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

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

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

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

  5. bzoj4033 [HAOI2015]树上染色——树形DP

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4033 树形DP,状态中加入 x 与父亲之间的边的贡献: 边权竟然是long long... ...

  6. BZOJ 4033 [HAOI2015]树上染色 ——树形DP

    可以去UOJ看出题人的题解. 这样的合并,每一个点对只在lca处被考虑到,复杂度$O(n^2)$ #include <map> #include <ctime> #includ ...

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

    题目描述 给你一棵\(n\)个点的树,你要把其中\(k\)个点染成黑色,剩下\(n-k\)个点染成白色.要求黑点两两之间的距离加上白点两两之间距离的和最大.问你最大的和是多少. \(n\leq 200 ...

  8. 【HAOI2015】树上染色 - 树形 DP

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

  9. BZOJ_4033_[HAOI2015]树上染色_树形DP

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

随机推荐

  1. sql语句之分组

    对聚合函数的结果进行筛选用having,不能用where

  2. csps模拟92数列,数对,最小距离题解

    题面:https://www.cnblogs.com/Juve/articles/11767225.html 数列: 简化题意:已知a,b,c,求满足$a*x+b*y=c$的$x+y$最小值 然后ex ...

  3. Maven远程仓库地址修改(精)

    国内最快的maven镜像  阿里云maven镜像 <repositories> <repository> <id>spring-snapshots</id&g ...

  4. SGI STL rope

    rope实现的接口可以参考这里. rope是可伸缩的string实现: 它们被设计为用于把string看作一个整体的高效操作 . 比如赋值.串联和子串的操作所花的时间差不多不依赖字符串的长度.与C的字 ...

  5. (一)PHP基础知识考察点

    1,PHP引用变量的考察点: 概念:引用就是用不同的名字访问同一个变量内容. 定义方式: 使用&符号. PHP引用变量的工作原理 这里有个COW  copy on write  用zval() ...

  6. yolo自己的数据集中LabelImg的安装出现No module named 'libs.resources'错误

    以下是完整的安装过程,如果出现No module named 'libs.resources',直接看第四点. 1.安装PyQt,在官网下载吧,否则pip install 要等好久 2.安装PyQtT ...

  7. django中写form表单时csrf_token的作用

    之前在学习django的时候,在template中写form时,出现错误.百度,google后要加{% csrf_token %}才可以,之前一直也没研究,只是知道要加个这个东西,具体是什么也不明白. ...

  8. Han Xin and His Troops(扩展中国剩余定理 Python版)

    Han Xin and His Troops(扩展中国剩余定理 Python版) 题目来源:2019牛客暑期多校训练营(第十场) D - Han Xin and His Troops 题意:   看标 ...

  9. windows安装vscode,配置golang环境

    出现的问题: 进行如下命令进行目录切换:cd %GOPATH%\src\github.com\golang我这里的GOPATH是在D:\GoPath,大家这里一定要注意些如果src目录下面没有gith ...

  10. Windows的哈希

    Windows中有几种不同类型的哈希值,它们可能非常混乱. 可以在这两篇文章<LM, NTLM, Net-NTLMv2, oh my!>和<LM Hash and NT Hash & ...