#樹形dp#洛谷 1272 重建道路
阿新 • • 發佈:2021-09-29
樹形dp
題目
給出一個大小為 \(n\) 的樹,
問至少斷掉多少條邊使得存在一個大小為 \(m\) 的連通塊
\(n\leq 150\)
分析
設 \(dp[x][s]\) 表示以 \(x\) 為根的子樹至少斷掉多少條邊使得存在一個大小為 \(s\) 的連通塊
則 \(dp[x][s]=\min\{dp[x][s']+dp[y][s-s']\}\)
如果不選該子樹則要多斷一條邊,最後就是
\(\min\{dp[x][m]+[x>1]\}\)
程式碼
#include <cstdio> #include <cctype> #include <cstring> #define rr register using namespace std; const int N=161; struct node{int y,next;}e[N<<1]; int siz[N],as[N],dp[N][N],n,m,et=1,ans; inline signed iut(){ rr int ans=0; rr char c=getchar(); while (!isdigit(c)) c=getchar(); while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar(); return ans; } inline signed min(int a,int b){return a<b?a:b;} inline void dfs(int x,int fa){ siz[x]=1,dp[x][1]=0; for (rr int i=as[x];i;i=e[i].next) if (e[i].y!=fa){ dfs(e[i].y,x),siz[x]+=siz[e[i].y]; for (rr int o=siz[x]-siz[e[i].y];o;--o){ for (rr int j=siz[e[i].y];j;--j) dp[x][o+j]=min(dp[x][o+j],dp[x][o]+dp[e[i].y][j]); ++dp[x][o]; } } } signed main(){ n=iut(),m=iut(),memset(dp,42,sizeof(dp)); for (rr int i=1;i<n;++i){ rr int x=iut(),y=iut(); e[++et]=(node){y,as[x]},as[x]=et; e[++et]=(node){x,as[y]},as[y]=et; } dfs(1,0),ans=dp[1][m]; for (rr int i=2;i<=n;++i) ans=min(ans,dp[i][m]+1); return !printf("%d",ans); }