1. 程式人生 > 其它 >第 45 屆國際大學生程式設計競賽(ICPC)亞洲區域賽(南京)M Monster Hunter —— 樹形DP

第 45 屆國際大學生程式設計競賽(ICPC)亞洲區域賽(南京)M Monster Hunter —— 樹形DP

技術標籤:dp想法

This way

題意:

現在有一棵根為1的樹,你要將所有點消除,消除一個點i首先需要消除它的父親,然後消除i的代價是
在這裡插入圖片描述
也就是hp[i]+還未被消除的所有兒子的hp和
你有一種魔法可以無視所有規則消除掉一個點。
問你這個魔法的使用次數為i(0<=i<=n)次時,最少需要的代價是多少。

題解:

很明顯是樹形DP,但是列舉兒子的狀態轉移的話,時間複雜度會變成 n 3 n^3 n3,所以需要使用上下界優化
那麼消除當前數的時候,需要加上所有未被消除的兒子的值,因此DP需要三維
dp[i][j][k]表示到了第i個點,使用了j次魔法,當前點是否一開始就使用魔法消除時最小的代價。

那麼邊界值:
dp[x][1][0]=0
dp[x][0][1]=a[x]
然後轉移:
首先是這個點在一開始就被消除
dp[x][i+j][0]=min(dp[x][i+j][0],dp[x][i][0]+min(dp[ne][j][0],dp[ne][j][1]));
還有一種就是這個點按照常規的消除方法,它需要加上兒子的代價
dp[x][i+j][0]=min(dp[x][i+j][0],dp[x][i][0]+min(dp[ne][j][0],dp[ne][j][1]+a[ne]));

#include<bits/stdc++.h>
using namespace std;
#define ll long long 
const int N=2e3+5; ll dp[N][N][2],a[N]; const ll inf=1e18; vector<int>son[N]; int siz[N]; ll tmp[N]; void dfs(int x){ siz[x]=1; dp[x][0][0]=inf,dp[x][1][0]=0; //dp[x][0][1]=a[x]; int f=0; for(int ne:son[x]){ dfs(ne); for(int i=0;i<=siz[x]+siz[ne];i++)tmp[i]=
inf; for(int i=0;i<=siz[x];i++){ if(dp[x][i][0]==inf)continue; for(int j=0;j<=siz[ne];j++) tmp[i+j]=min(tmp[i+j],dp[x][i][0]+min(dp[ne][j][0],dp[ne][j][1])); } siz[x]+=siz[ne]; for(int i=0;i<=siz[x];i++)dp[x][i][0]=tmp[i]; } //for(int i=1;i<=siz[x];i++)dp[x][i][1]=dp[x][i][0]+a[x]; //int s=vec[x].size(); ll sum=0,v=0; dp[x][0][1]=a[x]; siz[x]=1; for(int ne:son[x]){ for(int i=0;i<=siz[x]+siz[ne];i++)tmp[i]=inf; for(int i=0;i<=siz[x];i++){ if(dp[x][i][1]>=inf)continue; for(int j=0;j<=siz[ne];j++) tmp[i+j]=min(tmp[i+j],dp[x][i][1]+min(dp[ne][j][0],dp[ne][j][1]+a[ne])); } siz[x]+=siz[ne]; for(int i=0;i<=siz[x];i++)dp[x][i][1]=tmp[i]; } } int main() { int t; scanf("%d",&t); while(t--){ int n,x; scanf("%d",&n); for(int i=1;i<=n;i++)son[i].clear(),siz[i]=0; for(int i=1;i<=n;i++) for(int j=0;j<=n;j++) for(int k=0;k<=1;k++) dp[i][j][k]=inf; for(int i=2;i<=n;i++) scanf("%d",&x),son[x].push_back(i); for(int i=1;i<=n;i++) scanf("%lld",&a[i]); dfs(1); for(int i=0;i<=n;i++) printf("%lld%c",min(dp[1][i][0],dp[1][i][1])," \n"[i==n]); } return 0; }