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

Input

第一行两个整数N,K。
接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。
输入保证所有点之间是联通的。
N<=2000,0<=K<=N

Output

输出一个正整数,表示收益的最大值。

Sample Input

5 2
1 2 3
1 5 1
2 3 1
2 4 2

Sample Output

17
【样例解释】
将点1,2染黑就能获得最大收益。

  动态规划的第一步——设计状态,f[i][j]表示以i节点为根的子树中染了j个黑点的"收益"。

  不过这样没有黑点的位置,这么多个点,总不可能用N进制来表示点的位置。所以只能换个思路。

  对于当前考虑的这棵子树,我知道染了j个节点,那么我知道在这棵子树内的白点数和子树外的白点数和黑点数。因此我可以计算出节点i到它的父节点的那条边的对答案的贡献,对于子节点转移到父节点就是一个用dp合并的过程,因此解决了状态转移的问题,时间复杂度为O(nk)。

  注意dp时不合法的状态一定不能转移(看代码吧,或者自己想想也可以,状态转移前有个if)

  (现在觉得以前的树归写得好丑)

Code

 /**
* bzoj
* Problem#4033
* Accepted
* Time:630ms
* Memory:17092k
*/
#include<iostream>
#include<fstream>
#include<sstream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<ctime>
#include<map>
#include<stack>
#include<set>
#include<queue>
#include<vector>
#ifndef WIN32
#define AUTO "%lld"
#else
#define AUTO "%I64d"
#endif
using namespace std;
typedef bool boolean;
#define inf 0xfffffff
#define smin(a, b) (a) = min((a), (b))
#define smax(a, b) (a) = max((a), (b))
template<typename T>
inline boolean readInteger(T& u) {
char x;
int aFlag = ;
while(!isdigit((x = getchar())) && x != '-' && x != -);
if(x == -) {
ungetc(x, stdin);
return false;
}
if(x == '-') {
aFlag = -;
x = getchar();
}
for(u = x - ''; isdigit((x = getchar())); u = u * + x - '');
u *= aFlag;
ungetc(x, stdin);
return true;
} ///map template starts
typedef class Edge{
public:
int end;
int next;
int w;
Edge(const int end = , const int next = , const int w = ):end(end), next(next), w(w){}
}Edge; typedef class MapManager{
public:
int ce;
int *h;
Edge *edge;
MapManager(){}
MapManager(int points, int limit):ce(){
h = new int[(const int)(points + )];
edge = new Edge[(const int)(limit + )];
memset(h, , sizeof(int) * (points + ));
}
inline void addEdge(int from, int end, int w){
edge[++ce] = Edge(end, h[from], w);
h[from] = ce;
}
inline void addDoubleEdge(int from, int end, int w){
addEdge(from, end, w);
addEdge(end, from, w);
}
Edge& operator [] (int pos) {
return edge[pos];
}
}MapManager;
#define m_begin(g, i) (g).h[(i)]
///map template ends template<typename T>class Matrix{
public:
T *p;
int lines;
int rows;
Matrix():p(NULL){ }
Matrix(int rows, int lines):lines(lines), rows(rows){
p = new T[(lines * rows)];
}
T* operator [](int pos){
return (p + pos * lines);
}
};
#define matset(m, i, s) memset((m).p, (i), (s) * (m).lines * (m).rows) int n, k;
MapManager g;
Matrix<long long> f;
int* size; inline void init() {
readInteger(n);
readInteger(k);
g = MapManager(n, * n);
f = Matrix<long long>(n + , k + );
size = new int[(const int)(n + )];
matset(f, , sizeof(long long));
for(int i = , a, b, c; i < n; i++) {
readInteger(a);
readInteger(b);
readInteger(c);
g.addDoubleEdge(a, b, c);
}
} void treedp(int node, int fa, int len) {
size[node] = ;
for(int i = m_begin(g, node); i != ; i = g[i].next) {
int& e = g[i].end;
if(e == fa) continue;
treedp(e, node, g[i].w);
size[node] += size[e];
for(int j = min(size[node], k); j >= ; j--) {
for(int s = ; s <= size[e] && s <= j; s++) {
if(j - s <= size[node] - size[e])
smax(f[node][j], f[node][j - s] + f[e][s]);
}
}
}
for(int i = ; i <= min(size[node], k); i++)
f[node][i] += (i * 1LL * (k - i) + (size[node] - i) * 1LL * (n - k - size[node] + i)) * len;
} inline void solve() {
treedp(, , );
printf(AUTO"\n", f[][k]);
} int main() {
init();
solve();
return ;
}

bzoj 4033 树上染色 - 树形动态规划的更多相关文章

  1. [BZOJ 4033] 树上染色

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

  2. [HAOI2015][bzoj 4033]树上染色(树dp+复杂度分析)

    [题目描述]有一棵点数为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. [BZOJ4033][HAOI2015]树上染色(树形DP)

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

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

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

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

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

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

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

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

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

随机推荐

  1. Linux的/etc/services文件的作用?

    4)端口分配 Linux系统的端口号的范围为0–65535,不同范围有不同的意义. 0 不使用 1--1023 系统保留,只能由root用户使用 1024---4999 由客户端程序自由分配 5000 ...

  2. RuntimeError: Object: Could not open SDE workspace

    客户环境,linux 终端里,使用arcpy.ListUsers() 报错:RuntimeError: Object: Could not open SDE workspace 经检查,问题在于 该机 ...

  3. flask中cookie,session的存储,调用,删除 方法(代码demo)

    # -*- encoding: utf-8 -*- # cookie,session的存储,调用,删除 from flask import Flask,make_response,request,se ...

  4. Git 安装及使用小结

    Git 安装及使用小结 a:focus { outline: thin dotted #333; outline: 5px auto -webkit-focus-ring-color; outline ...

  5. TCP报文

    源端口和目的端口: 各占16位 ,服务相对应的源端口和目的端口. 序列号: 占32位,它的范围在[0~2^32-1],序号随着通信的进行不断的递增,当达到最大值的时候重新回到0在开始递增.TCP是面向 ...

  6. 查询删除安装rpm -qa | grep -i wrapname

    查询:rpm -qa | grep -i wrapname 删除:sudo rpm -ev wrapname 删除依赖:sudo rpm -ev --nodeps mysql-libs-5.6.60- ...

  7. 关于找不到类org/apache/commons/lang/xwork/StringUtils的问题

    在替换最新版的 struts2包的解决过程中.遇到 找不到这两个包org/apache/commons/lang/xwork/StringUtils.org/apache/commons/lang/x ...

  8. 微软官方出的各种dll丢失的修复工具

    例如 :因为计算机中丢失 api-ms-win-crt-runtime-l1-1-0.dll.尝试重新安装该程序以解决此问题. 软件名称: Visual C++ Redistributable for ...

  9. PHP 常用命令行

    1.PHP运行指定文件 php -f test.php (-f 可省略) 2.命令行直接运行PHP代码 php -r "phpinfo();" 如果结果太长,还可以 php -r ...

  10. windows 环境下安装elasticsearch ,ik,head,marvel

    elasticsearch  自带的中分分词器将会使中文分成一个一个的单词,需要安装ik分词等,ik分词分为 ik_smart(粗粒度分词),ik_max_word(细粒度分词)两种模式. 1:首先安 ...