有一棵点数为N的树,树边有边权。给你一个在0~N之内的正整数K,你要在这棵树中选择K个点,将其染成黑色,并
将其他的N-K个点染成白色。将所有点染色后,你会获得黑点两两之间的距离加上白点两两之间距离的和的收益。
问收益最大值是多少。
标签:enter clu 注意 题目 continue sizeof sam algorithm scanf
#include<iostream> #include<stdio.h> #include<stdlib.h> #include<algorithm> #include<cstring> #define ll long long const int MAXN=3005; using namespace std; ll dp[MAXN][MAXN]; ll size[MAXN]; ll n,k,num=0; struct edge{ ll first; ll next; ll to; ll quan; }a[MAXN*2]; void addedge(ll from,ll to,ll quan){ a[++num].to=to; a[num].quan=quan; a[num].next=a[from].first; a[from].first=num; } void dfs(ll now,ll f){ size[now]=1; for(ll i=a[now].first;i;i=a[i].next){ ll to=a[i].to; if(to==f) continue; dfs(to,now); size[now]+=size[to]; } ll fill=1; for(ll i=a[now].first;i;i=a[i].next){ ll to=a[i].to,quan=a[i].quan; if(to==f) continue; for(ll have=fill;have>=0;have--){ for(ll j=min(size[to],k);j>=0;j--){ if(dp[to][j]>=0&&have+j<=k){ dp[now][j+have]=max(dp[now][j+have],dp[now][have]+dp[to][j]+quan*j*(k-j)+(ll)(quan*(size[to]-j)*(n-k-size[to]+j))); } } } fill=min(k,fill+size[to]); } } int main(){ scanf("%lld%lld",&n,&k); memset(dp,0,sizeof(dp)); memset(size,0,sizeof(size)); for(int i=1;i<n;i++){ ll x,y,z;scanf("%lld%lld%lld",&x,&y,&z); addedge(x,y,z); addedge(y,x,z); } dfs(1,0); printf("%lld\n",dp[1][k]); }
标签:enter clu 注意 题目 continue sizeof sam algorithm scanf
原文地址:http://www.cnblogs.com/renjianshige/p/7327872.html