这道题也是我看了题解才懂得,其实并不是很难,题目意思是,有一棵树,每个节点上有一个权值,从根节点走到尾节点算是一个链,链的权值为链上节点的权值和,但是有个要求,就是每个权值只能被算一次,问你前K个链的权值和的最大值是多少。
这道题的解题思路就是搜索,先搜索出最大的一条链,然后把最大的这条链上的权值都置为零,然后以此类推,再找出剩下最大的,最后将所有的链排序,将前K个相加即可。代码模仿大神,神奇的地方在于DFS过程的简洁,再次膜拜。
/*#########################################################################
# File Name: game.cpp
# Author: CaoLei
# Created Time: 2015/7/11 10:39:37
#########################################################################*/
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <set>
#include <queue>
#include <map>
using namespace std;
#define MAX(x,y) (((x)>(y))?(x):(y))
#define MIN(x,y) (((x)<(y))?(x):(y))
#define N 100010
#define pi acos(-1.0)
#define inf 100000000
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
int n,k,it;
int fnext[N],val[N];
struct edge{
int u,v;
int next;
}e[N];
priority_queue<ll>q;
void addedge(int u,int v){
e[it].u=u;
e[it].v=v;
e[it].next=fnext[u];
fnext[u]=it++;
}
ll dfs(int root){
ll maxval=0;
for(int i=fnext[root];i!=-1;i=e[i].next){
int v=e[i].v;
ll val=dfs(v);
if(val>maxval){
if(maxval!=0) q.push(maxval);
maxval=val;
}
else q.push(val);
}
return maxval+val[root];
}
int main(){
//freopen("in.txt","r",stdin);
int t,cas,a,b;
scanf("%d",&t);
for(cas=1;cas<=t;cas++){
it=1;
printf("Case #%d: ",cas);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%d",&val[i]);
fnext[i]=-1;
}
for(int i=1;i<n;i++){
scanf("%d%d",&a,&b);
addedge(a,b);
}
while(!q.empty()) q.pop();
ll ans=dfs(1);
for(int i=2;i<=k&&!q.empty();i++){
ans+=q.top();
q.pop();
}
printf("%lld\n",ans);
}
return 0;
}