P3177 [HAOI2015] 树上染色 题解

题目传送门\small\color{#88FF88}\textbf{\textsf{题目传送门}}


General Idea\Large\color{skyblue}\mathcal General \ Idea

树形 dp,主要就是状态与转移方程。

设总共要染色 VV 个节点,该题中,我们可以设 dpu,qdp_{u,q} 为以 uu 为根节点的树内,染色 qq 个节点的最大收益。

对于节点的第 ii 条边,设已经在当前点及其子树染色 jj 个点,在以当前边指向节点 vv 为根的子树 tvt_v 内,选了 kk 条边。那么状态转移方程为:(以下设以 uu 为根的树的节点个数为 sus_u,当前边权为 ww

dpu,j+k=maxjsu,ksv(dpu,j+k,dpu,j+dpv,k+w×k×(Vk)+w×(svk)×(nsv(Vk)))dp_{u,j+k}=\max\limits_{j\leq s_u,k\leq s_v}(dp_{u,j+k},dp_{u,j}+dp_{v,k}+w\times k\times(V-k)+w\times(s_v-k)\times(n-s_v-(V-k)))

接下来分别解释意思:

  • dpu,j+dpv,kdp_{u,j}+dp_{v,k}dpu,j+kdp_{u,j+k} 可以继承他们。下面计算 ww 被计算次数。
  • w×k×(Vk)w\times k\times(V-k)。在 tvt_v 内染色 kk 个节点,tvt_v 外有 VkV-k 个节点被染色,边权 ww 就会被计算 k×(Vk)k\times(V-k) 次(乘法原理)。
  • w×(svk)×(nsv(Vk))w\times(s_v-k)\times(n-s_v-(V-k))tvt_v 内会剩下 svks_v-k 个节点未被染色,tvt_v 外有 nsvn-s_v 个节点,有nsv(Vk)n-s_v-(V-k) 个未染色节点,边权 ww 会被计算 (svk)×(nsv(Vk))(s_v-k)\times(n-s_v-(V-k)) 次(同上)。

Code\Large\color{skyblue}\mathcal Code

#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e3+10;
struct LovelyLzw//lzw 敲可爱
{
	int v,ne,w;
}ee[N*2];
int hd[N],ne,s[N],V,n;
ll dp[N][N];
void ae(int u,int v,int w)//链式前向星
{
	ee[++ne]={v,hd[u],w};
	hd[u]=ne;
}
void dfs(int u)
{
	s[u]=1;
	for(int i=hd[u];i;i=ee[i].ne)
	{
		ll v=ee[i].v,w=ee[i].w;
		if(s[v]) continue;dfs(v);
		for(int j=s[u];j>=0;j--)//要倒序枚举 否则会被算多边
			for(int k=min(s[v],V-j);k>=0;k--)
				dp[u][j+k]=max(dp[u][j+k],dp[u][j]+dp[v][k]+w*k*(V-k)+w*(s[v]-k)*(n-(V-k)-s[v]));//状态转移
		s[u]+=s[v];//更新树大小
	}
}
int main() {
    ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
    cin>>n>>V;
    for(int i=1,x,y,w;i<n;i++)cin>>x>>y>>w,ae(x,y,w),ae(y,x,w);
	dfs(1);
	cout<<dp[1][V];
    return 0;
}

本文作者:cjrqwq

本文链接:https://www.cnblogs.com/yfzqwq/p/18492823

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   cjrqwq  阅读(24)  评论(0编辑  收藏  举报  
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
展开
  1. 1 404 not found REOL
404 not found - REOL
00:00 / 00:00
An audio error has occurred.