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;
有一棵点数为 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;
}