洛谷P1272 重建道路 树形dp

2019-07-11 10:38:42 浏览数 (1)

f[ i ][ j ] 表示 i 为根节点选择 j 个点要去掉的最小边数。

一开始初始化所有边都去掉,只剩下本身一个点,值等于度数,根据是否为根结点加减一。

然后dp时-1是应为要加上 u 到 v 的一条边,dp表示要去掉的边,则要去掉的一条边则减一 

代码语言:javascript复制
//洛谷P1272 重建道路
//树形dp 
#include <bits/stdc  .h>
using namespace std;
const int maxn = 155;
struct N{
	int nxt,v;
}ed[maxn<<2];
int dp[maxn][maxn],du[maxn];
int head[maxn],cnt,n,p,ans=0x7ffffff;
void add(int u,int v){
	cnt  ;
	ed[cnt].v = v;
	ed[cnt].nxt = head[u];
	head[u] = cnt; 
}
void dfs(int u,int fa){
	dp[u][1] = du[u] - (fa!=0);//u为根节点选择i个点要去掉的最小边数 
	for(int v,i=head[u];i;i=ed[i].nxt){
		v = ed[i].v;
		if(v==fa)continue;
		dfs(v,u);
		for(int j=p;j>=1;j--){
			for(int k=1;k<j;k  ){
				dp[u][j] = min(dp[u][j],dp[u][k] dp[v][j-k]-1);
				//一开始把所有边都删了,连接v u 还需要加上一条边
				//所以去掉的边就少一条 	
			}
		}
		
	}
	ans = min(ans,dp[u][p] (fa!=0)); //不是根结点 还要去掉父结点和自己的连线 
}
int main()
{		
	
	scanf("%d %d",&n,&p);
	for(int i=1;i<n;i  ){
		int u,v;
		scanf("%d %d",&u,&v);
		du[u]  ; du[v]  ;
		add(u,v);	add(v,u);
	}
	memset(dp,0x3f,sizeof(dp));
	dfs(1,0);
	printf("%d",ans);
	return 0;
}
dp

0 人点赞