【HAOI2015】T1

Description
  有一棵点数为 N 的树,树边有边权。给你一个在 0~ N 之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间的距离的和的收益。问收益最大值是多少。
Input
  第一行包含两个整数N,K。
  接下来N-1行每行三个正整数fr,to,dis,表示该树中存在一条长度为dis的边(fr,to)。输入保证所有点之间是联通的。
Output
  输出一个正整数,表示收益的最大值。
Sample Input
3 1
1 2 1
1 3 2
Sample Output
3
Hint
t1.in
5 2
1 2 3
1 5 1
2 3 1
2 4 2
t1.out
17
【样例解释2】在第二个样例中,将点1,2染黑就能获得最大收益。 
【数据约定】
  对于30%的数据,N<=20; 
  对于50%的数据,N<=100; 

  对于100%的数据,0<=K<=N<=2000;



很容易看出是树形DP

但是怎么做?

设F[i][j]代表以i为根的子树染j个黑点的最大收益。

但我们发现,更新F[i][j]时要考虑i点的不同子树中点对的连接

(即加上一个子树的收益时还要加上子树中各点到其他同色点的距离)

这样的话就不太好做,我们还必须考虑黑点(白点)到i的总距离和,F就必须增加2维。


这时考虑状态为局部的答案就不太好做了,于是我们转而来考虑状态对答案的贡献。

设F[i][j]代表i为根的子树染j个黑点对答案的最大贡献。

每次加入一个子树新增的收益(以i为根的子树内)只会是 子树中的收益+i连向子树的边处于各个同色点对的次数。

次数就好算了,只有子树中黑点到子树外黑点(白点也一样)才会经过这条边。

tims=子树黑点数*(k-子树黑点数)+ 子树白点数*(k-子树黑白数);

代码:

//#pragma G++ optimize(2)
//#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const LL N=2005;
LL n,m,a,b,c,d,e,limit;
inline int read()
{
	char t;int u=0,k=1;t=getchar();
	while(t<'0'||t>'9'){if(t=='-')k=-1;t=getchar();}
	while(t>='0'&&t<='9'){u=u*10+t-'0';t=getchar();}
	return u*k;
}
LL size[N],F[N][N],G[N];
vector <LL> Map[N],len[N];
void DP(LL now,LL fa)
{
	size[now]=1;
	for(LL i=0;i<Map[now].size();i++)
	{
		LL a=Map[now][i],b=len[now][i];
		if(fa==a)continue;
		DP(a,now);
		memcpy(G,F[now],sizeof F[now]);
		for(LL j=0;j<=size[now];j++)
			for(LL v=0;v<=size[a];v++)
				F[now][j+v]=max(F[now][j+v],G[j]+F[a][v]+b*(v*(m-v)+(size[a]-v)*(n-m+v-size[a])));
		size[now]+=size[a];
	}
}
int main()
{
	n=read();m=read();
	for(LL i=1;i<n;i++)
	{
		a=read();b=read();c=read();
		Map[a].push_back(b);Map[b].push_back(a);
		len[a].push_back(c);len[b].push_back(c);
	}
	DP(1,0);cout<<F[1][0];
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值