博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
树上染色题解
阅读量:5037 次
发布时间:2019-06-12

本文共 2773 字,大约阅读时间需要 9 分钟。

题目描述

有一棵点数为n的树,树边有边权。将m个点染成黑色,并将其他的点染成白色。会获得黑点两两之间的距离和加上白点两两之间的距离和的收益。问收益最大值是多少。

输入输出格式

输入格式:

 

第一行两个整数n、m。接下来n-1行,每行三个整数a、b、c,表示有一条树边连接a、b,长度为c。

 

输出格式:

 

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

 

题解

  由题目我们可以考虑动态规划,令f[i][j]表示以i为根节点的子树上有j个结点为黑色可以得到的最大贡献。这就成了一个树上背包问题了。

  对于f[i][j]这个状态,除i以外的所有点可以被分为两类,一类是在i 的子树上的,另一类是在i的子树外的。而在这两个集合中各取一个点相连一定会经过边(i, father[i])我们可以算出在此时(i,father[i])产生的收益是(设子树大小为size[i])子树上的黑点个数(j)与子树外的黑点个数(m - j)的乘积乘上这条边的边权(w[i])加上子树上白点的个数(size[i] - j)乘以子树外白点的个数(n - m - size[i] + j)再乘以边权,这些贡献是在加入了根节点以后才产生的新的贡献,与子树上黑白点如何分配无关。

  然后,我们再来考虑子树上黑白点的分配方法,由于之前的子树分配对后面的子树如何分配没有影响,我们可以把子树分为两类,一类是已经确定大小的,一类是还没有确定大小的,而这其中产生的贡献即为当前讨论的子树上的黑点个数可以带来的贡献值,和这颗子树以外的点可以带来的贡献值,而这颗子树以外的点可以带来的贡献值,我们就只能先计算那些我们已经划分好了的,而其余的我们可以留在后面的子树再继续划分(这是我觉得这道题最玄学的地方),所以我们状态的转移要像这样写:

void Dp(int u)     {         size[u] = 1;         for(int i = Head[u]; i != -1; i = Next[i])             {                 int v = To[i];                 if(size[v] != 0)    continue;                 Dp(v);                 memset(g, 0, sizeof(g));                 for(int t = 0; t <= min(m, size[u]); t ++)                     for(int j = 0; j <= min(m, size[v]) && j +t <= m; j ++)                         g[t + j] = max(g[t + j],f[u][t] + f[v][j] + (long long) (j * (m - j) + (size[v] - j) * (n - m - (size[v] - j))) * w[i]);                 for(int j = 0; j <= m; ++ j)    f[u][j] = g[j];                 size[u] += size[v];             }     }

 

 

代码

#include
using namespace std; const int MAX = 2005; long long f[MAX][MAX], g[MAX]; int Head[MAX], To[MAX << 1], Next[MAX << 1], edgenum = 0, w[MAX << 1]; int n, m; void Add_edge(int from, int to, int c) { Next[++ edgenum] = Head[from]; Head[from] = edgenum; To[edgenum] = to; w[edgenum] = c; } int size[MAX]; void Dp(int u) { size[u] = 1; for(int i = Head[u]; i != -1; i = Next[i]) { int v = To[i]; if(size[v] != 0) continue; Dp(v); memset(g, 0, sizeof(g)); for(int t = 0; t <= min(m, size[u]); t ++) for(int j = 0; j <= min(m, size[v]) && j +t <= m; j ++) g[t + j] = max(g[t + j],f[u][t] + f[v][j] + (long long) (j * (m - j) + (size[v] - j) * (n - m - (size[v] - j))) * w[i]); for(int j = 0; j <= m; ++ j) f[u][j] = g[j]; size[u] += size[v]; } } int main() { memset(Head, -1, sizeof(Head)); int x, y, z; scanf("%d%d", &n, &m); for(int i = 1; i < n; ++ i) { scanf("%d%d%d", &x, &y, &z); Add_edge(x, y, z); Add_edge(y, x, z); } Dp(1); printf("%lld\n", f[1][m]); return 0; }

 

 

 

转载于:https://www.cnblogs.com/2020pengxiyue/p/9314817.html

你可能感兴趣的文章
pig自定义UDF
查看>>
输入名字显示其生日,没有则让输入生日,做记录
查看>>
爬虫综合大作业
查看>>
HTML canvas原生js实现鼠标画图
查看>>
《程序设计入门——C语言》翁恺老师 第一周编程练习记录
查看>>
IE8兼容性视图问题
查看>>
Kubernetes 运维学习笔记
查看>>
Centos6.9下RabbitMQ集群部署记录
查看>>
Python之基本的日期与时间转换 datetime、 dateutil模块
查看>>
android studio
查看>>
色彩大全,色彩配色大全
查看>>
mpeg文件格式分析 分类: 生活百科 201...
查看>>
并查集 经典 畅通工程
查看>>
Spark MLlib 之 Naive Bayes
查看>>
synchronized关键字
查看>>
自定义DataSourceProvider
查看>>
客户端向服务器提交数据,表单形式
查看>>
工具-VS2015前端开发工具简介
查看>>
php修改SESSION的有效生存时间
查看>>
spring security 11种过滤器介绍
查看>>