1. 程式人生 > >【洛谷P1272】 重建道路

【洛谷P1272】 重建道路

void 另一個 節點 編號 include 構建 ble add next

重建道路

題目鏈接

一場可怕的地震後,人們用N個牲口棚(1≤N≤150,編號1..N)重建了農夫John的牧場。由於人們沒有時間建設多余的道路,所以現在從一個牲口棚到另一個牲口棚的道路是惟一的。因此,牧場運輸系統可以被構建成一棵樹。John想要知道另一次地震會造成多嚴重的破壞。有些道路一旦被毀壞,就會使一棵含有P(1≤P≤N)個牲口棚的子樹和剩余的牲口棚分離,John想知道這些道路的最小數目。

顯然是一道樹形DP

然後看題解

樹上分組背包問題

dp[u][i][j]表示以u為根的子樹中,前i個子樹中留下j個的最小花費

首先,dp[u][size[u]][1]=son_num[u]

以u為節點的子樹留下1個節點的花費為u的子樹個數

dp[u][i][j]=min(dp[u][i][j],dp[u][i-1][j-k]+dp[v][size[v]][k]-1);

i這一維可以滾動數組滾掉

#include<iostream>
#include<cstring>
#include<cstdio> 
#define N 155
int n,p,dp[N][N],out[N],in[N];
struct NODE{
    int to,next;
} e[N];
int Head[N],num;
inline void add(int x,int y){
    e[++num].to=y;
    e[num].next
=Head[x]; Head[x]=num; } inline int read(){ int x=0; char c=getchar(); while(c<0||c>9) c=getchar(); while(0<=c&&c<=9) { x=(x<<3)+(x<<1)+c-0; c=getchar(); } return x; } inline int min(int a,int b){ return a<b?a:b; } int dfs(int u){ dp[u][
1]=out[u]; int sum=1; for(int i=Head[u];i;i=e[i].next){ int v=e[i].to; int sz=dfs(v); sum+=sz; for(int j=sum;j>=0;j--) for(int k=0;k<=min(sz,j);k++){ dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]-1); } } dp[u][sum]=0; return sum; } int main() { memset(dp,0x3f,sizeof(dp)); scanf("%d%d",&n,&p); int x,y; for(int i=1;i<n;i++){ x=read(); y=read(); add(x,y); out[x]++; in[y]++; } int st; for(int i=1;i<=n;i++) if(!in[i]) { st=i; break; } dfs(st); int ans=0x7fffffff; for(int i=1;i<=n;i++) ans=min(ans,dp[i][p]+(i==st?0:1)); printf("%d\n",ans); return 0; }

【洛谷P1272】 重建道路