这道题细节很多,调了很长时间,设mx[u][j]表示以u为根的子树,切j刀后,这颗子树中与u连通的所有节点的最大权值,包括u。考虑每颗子树的决策,要么切掉,要么连上。
附用例:
4 1
-3 -2 1 1
1 2
2 3
1 4
4 2
-3 -2 1 1
1 2
2 3
1 4
5 2
1 2 3 4 5
1 2
2 3
3 4
4 5
6 2
-3 1 -2 3 4 0
1 2
1 3
2 4
3 5
3 6
6 3
-3 1 -2 3 4 0
1 2
1 3
2 4
3 5
3 6
6 4
-3 1 -2 3 4 0
1 2
1 3
2 4
3 5
3 6
6 5
-3 1 -2 3 4 0
1 2
1 3
2 4
3 5
3 6
4 2
1 2 3 4
1 2
2 3
3 4
10 4
-1 2 -3 4 -5 6 -7 8 -9 10
1 2
2 4
2 5
2 6
1 3
3 8
3 7
7 9
7 10
10 8
-1 2 -3 4 -5 6 -7 8 -9 10
1 2
2 4
2 5
2 6
1 3
3 8
3 7
7 9
7 10
ans:
-4 1
-5 1
1 12
-5 4
-5 4
-5 4
-3 4
1 7
-23 16
-16 10
#include <iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#define N 1005
using namespace std;
vector<int>edge[N];
int weight[N],mx[N][25],mn[N][25],n,k,ansmx,ansmn;
int dfs(int u,int fa)
{
int i,len=edge[u].size(),v,j,l,sum=0,nums;
mn[u][0]=mx[u][0]=weight[u];
for(i=0;i<len;i++){
v=edge[u][i];
if(v==fa) continue;
if(u==2)
u=2;
sum+=(nums=dfs(v,u));
for(j=min(k,sum);j>=0;j--){
int tmp1=-999999999,tmp2=999999999;
for(l=0;l<j && l<nums;l++){
tmp1=max(tmp1,max(mx[u][j-l-1],mx[u][j-l]+mx[v][l]));
tmp2=min(tmp2,min(mn[u][j-l-1],mn[u][j-l]+mn[v][l]));
}
if(l<nums && j==l) tmp1=max(tmp1,mx[u][j-l]+mx[v][l]) , tmp2=min(tmp2,mn[u][j-l]+mn[v][l]);
mx[u][j]=tmp1;
mn[u][j]=tmp2;
}
}
for(j=(u!=1);j<=k && j<=n-sum-1;j++){
ansmx=max(ansmx,mx[u][k-j]);
ansmn=min(ansmn,mn[u][k-j]);
}
return sum+1;
}
int main()
{
while(~scanf("%d%d",&n,&k)){
memset(mx,-50,sizeof(mx));
memset(mn,50,sizeof(mn));
ansmx=mx[0][0]; ansmn=mn[0][0];
int i;
for(i=1;i<=n;i++) edge[i].clear();
for(i=1;i<=n;i++) scanf("%d",weight+i);
for(i=1;i<n;i++){
int a,b;
scanf("%d%d",&a,&b);
edge[a].push_back(b);
edge[b].push_back(a);
}
dfs(1,0);
printf("%d %d\n",ansmn,ansmx);
}
return 0;
}