ρars/ey 題解

zxh923發表於2024-08-08

給個連結:ρars/ey

我們考慮一個樹上揹包。

\(f_{u,i}\) 表示在 \(u\) 號節點的子樹內刪除 \(i\) 個點的最小代價。顯然有答案為 \(f_{1,siz_1-1}\)

接下來我們考慮轉移。看這一張圖:

這裡紅圈內的東西為當前的 \(siz_u\),綠圈部分為 \(siz_j\)

我們列舉 \(x\)\(u\) 子樹內已經被刪掉的點的數量。考慮 \(x\) 的上界為紅圈加綠圈減去 \(u\)\(u\)兒子

所以是 \(siz_u+siz_j-cnt-1\),其中 \(cnt\) 為當前是 \(u\) 的第幾個兒子。

然後再列舉一個 \(y\),代表 \(j\) 子樹內刪掉點的數量。

於是我們有 \(f_{u,x}=\min(f_{u,x},f_{u,x-y}+f_{j,y})\)

接著就是在跑完所有兒子後,再把剩下的點處理掉。具體就是列舉一個 \(i\),然後 \(f_{u,siz_u-1}=\min(f_{u,siz_u-1},f_{u,i}+a_{siz_u-i-1})\),其中 \(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;
}