ρars/ey题解
题目描述
给定一颗有 n 个节点的有根树,其中根节点是 1。你可以进行若干次以下操作:
- 选择一个节点,删去其子树内除其以外的点。
此操作的代价为 fi,其中 i 是你选择的节点子树大小。
你希望删掉除了 1 以外的所有点,请问代价的最小值是多少?
输入格式
第一行一个正整数 n。
第二行 n−1 个正整数,第 i 个表示 fi+1。
接下来 n−1 行,每行两个正整数,表示一条树边。
输出格式
一行一个正整数表示答案。
输入输出样例
输入 #1复制
8 11000 18640 32793 36187 45104 64932 66425 6 8 3 6 3 7 1 8 1 4 3 5 2 7
输出 #1复制
63744
说明/提示
【样例解释】
先删除节点 8 的子树内除了它自身的 5 个点,再删除节点 1 的子树内除了它自身的 2 个点,代价为 f6+f3=63744。可以证明这是最小的代价。
【数据范围】
对于所有数据,保证 1≤n≤5000,1≤fi≤109。
测试点编号1∼23∼67∼8910∼1213∼1415∼20 n≤ 815400400400 特殊限制 ABC
A:保证树上所有点度数均小于等于 2,其中 1 号点度数为 1。
B:保证树上只有 1 号点度数大于等于 2。
C:保证树随机生成,随机生成方式是,对于 i≥2,从 [1,i−1] 中随机一个整数 x,在 x 与 i 之间连边。然后随机打乱所有节点的编号。
附件下载
T2ex1.in222B
T2ex2.in89.58KB
思路
树形DP+优化。
代码见下
#include<bits/stdc++.h>
using namespace std;
long long n,a[5005],b[5005],u,vv,f[5005][5005],ef[5005];
vector<long long> v[5005];
void abc(long long a1,long long b1){
f[a1][0]=0;
ef[a1]=1;
for(int i=0;i<v[a1].size();i++){
long long tt=v[a1][i];
if(tt!=b1){
abc(tt,a1);
for(int j=ef[a1];j>=0;j--){
for(int k=0;k<=ef[tt];k++){
f[a1][j+k]=min(f[a1][j+k],f[a1][j]+f[tt][k]);
}
}
ef[a1]+=ef[tt];
}
}
for(int i=0;i<ef[a1];i++) {
f[a1][ef[a1]-1]=min(f[a1][ef[a1]-1],f[a1][i]+a[ef[a1]-i]);
}
return ;
}
void abcd(long long a1,long long b1){
b[a1]=1;
for(int i=0;i<v[a1].size();i++){
long long tt=v[a1][i];
if(tt!=b1){
abcd(tt,a1);
b[a1]+=b[tt];
}
}
return ;
}
int main(){
cin>>n;
for(int i=2;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n-1;i++){
cin>>u>>vv;
v[u].push_back(vv);
v[vv].push_back(u);
}
memset(f,62,sizeof(f));
abcd(1,0);
abc(1,0);
cout<<f[1][n-1]<<endl;
return 0;
}

浙公网安备 33010602011771号