1. 程式人生 > 實用技巧 >CF1249F Maximum Weight Subset (樹形dp)

CF1249F Maximum Weight Subset (樹形dp)

這道題的狀態可以設計為f[i][j]表示在以i為根的子樹上,深度最小為j的最大值。這個深度是相對於子樹的深度

因此我們列舉深度去更新當前子樹答案,在第一次更新的時候,先去求深度恰好為j的答案,之後倒序取一遍max就是答案

如果深度為0,就是選擇根節點,那麼只要把所有子樹中>=k的位置選進來就行(這裡的k已經先行+1)

如果深度不為0,那麼我們就去列舉子樹,表示深度為j的點在哪個子樹上。但是在這個更新中,其實我們求取的並不一定就是物理意義為深度恰好為j,但這並不影響答案

,之後只需要對其他子樹列舉距離大於等於k並且深度不超過j的答案疊加即可,可能有人會有疑惑說其他子樹之前是否會距離不足k,這是顯然不可能的,因為我們有max約束,具體可以看程式碼領會

因為我們枚舉了深度為j的在哪個子樹,所以我們列舉完了所有的答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> pll;
const int N=2e5+10;
int a[N];
vector<int> g[N];
int h[N],e[N],ne[N],idx;
int f[500][500];
int n,k;
void add(int a,int b){
    e[idx]=b,ne[idx]=h[a],h[a]=idx++;
}
void dfs(int u,int fa){ int i; for(i=h[u];i!=-1;i=ne[i]){ int j=e[i]; if(j==fa) continue; dfs(j,u); } for(i=0;i<201;i++){ if(i==0){ f[u][0]=a[u]; for(int j=h[u];j!=-1;j=ne[j]){ int v=e[j];
if(v==fa) continue; f[u][0]+=f[v][max(0,k-1)]; } } else{ for(int j=h[u];j!=-1;j=ne[j]){ int v=e[j]; if(v==fa) continue; int dis=f[v][i-1]; for(int x=h[u];x!=-1;x=ne[x]){ int d=e[x]; if(d==v||d==fa) continue; dis+=f[d][max(i-1,k-i-1)]; } f[u][i]=max(f[u][i],dis); } } } for(i=201;i>=0;i--) f[u][i]=max(f[u][i+1],f[u][i]); } int main(){ ios::sync_with_stdio(false); int i,j; cin>>n>>k; k++; memset(h,-1,sizeof h); for(i=1;i<=n;i++) cin>>a[i]; for(i=1;i<n;i++){ int u,v; cin>>u>>v; add(u,v); add(v,u); } dfs(1,-1); cout<<f[1][0]<<endl; return 0; }
View Code