ρ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

T2ex1.out7B

T2ex2.out9B

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;
}

posted @ 2025-10-14 21:10  bz02_2023f2  阅读(10)  评论(0)    收藏  举报  来源