ρars/ey 题解

给个链接:ρars/ey

我们考虑一个树上背包。

fu,i 表示在 u 号节点的子树内删除 i 个点的最小代价。显然有答案为 f1,siz11

接下来我们考虑转移。看这一张图:

这里红圈内的东西为当前的 sizu,绿圈部分为 sizj

我们枚举 xu 子树内已经被删掉的点的数量。考虑 x 的上界为红圈加绿圈减去 uu儿子

所以是 sizu+sizjcnt1,其中 cnt 为当前是 u 的第几个儿子。

然后再枚举一个 y,代表 j 子树内删掉点的数量。

于是我们有 fu,x=min(fu,x,fu,xy+fj,y)

接着就是在跑完所有儿子后,再把剩下的点处理掉。具体就是枚举一个 i,然后 fu,sizu1=min(fu,sizu1,fu,i+asizui1),其中 i 为代价。

代码:

#include<bits/stdc++.h>
#define int long long
#define N 5005
#define M 10005
using namespace std;
int n,a[N],siz[N],f[N][N];
int h[N],e[M],ne[M],idx;
//f_{u,i}表示u节点子树删了i个的代价 
void add(int a,int b){
	e[idx]=b;ne[idx]=h[a];h[a]=idx++;
}
void dfs(int u,int fa){
	siz[u]=1;
	int cnt=0;
	for(int i=h[u];~i;i=ne[i]){
		int j=e[i];
		if(j==fa)continue;
		dfs(j,u);
		cnt++;
		for(int x=siz[u]+siz[j]-cnt-1;x;x--){
			for(int y=max(x-siz[u],1ll);y<=x&&y<siz[j];y++){
				f[u][x]=min(f[u][x],f[u][x-y]+f[j][y]);
			}
		}
		siz[u]+=siz[j];
	}
	for(int i=0;i<=siz[u]-cnt-1;i++){
		f[u][siz[u]-1]=min(f[u][siz[u]-1],f[u][i]+a[siz[u]-i-1]);
	}
}
signed main(){
	cin>>n;
	for(int i=1;i<n;i++){
		cin>>a[i];
	}
	memset(h,-1,sizeof h);
	for(int i=1;i<n;i++){
		int a,b;
		cin>>a>>b;
		add(a,b);add(b,a);
	}
	memset(f,0x3f,sizeof f);
	for(int i=1;i<=n;i++){
		f[i][0]=0;
	}
	dfs(1,0);
	cout<<f[1][siz[1]-1];
	return 0;
}
posted @   zxh923  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示