給個連結:ρ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;
}