其他分享
首页 > 其他分享> > #树形dp#洛谷 1272 重建道路

#树形dp#洛谷 1272 重建道路

作者:互联网

题目

给出一个大小为 \(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);
}

标签:洛谷,min,int,1272,断掉,条边,include,dp
来源: https://www.cnblogs.com/Spare-No-Effort/p/15354489.html