码迷,mamicode.com
首页 > 其他好文 > 详细

[Codeforces 440D]Berland Federalization

时间:2017-12-31 16:41:54      阅读:101      评论:0      收藏:0      [点我收藏+]

标签:turn   个数   for   make   pre   ret   pair   line   复杂   

题目大意:给你一棵n个节点的树,现在要你删除尽可能少的边,使得剩余一个节点数刚好为k的子树。你需要输出节点数和删除的边的编号。

解题思路:树形dp。

设dp[i][j]和v[i][j]表示以i为根的子树中删除j个节点最少删的边数,和其所需删除的边对应的(点,删除的节点个数),用一个pair存储。

那么转移状态的时候类似于背包问题。

dp[i][j]=min{dp[s][k]+dp[i][j-k]}(s为i的儿子)。

更新答案的同时暴力更新v即可。

最后搜索根,注意如果根不为1,则需要把根与它的父亲的连边也去掉,即答案要+1。

时间复杂度$O(n^3)$。

C++ Code:

#include<cstdio>
#include<cctype>
#include<vector>
#include<cstring>
#define N 405
using namespace std;
vector<pair<int,int> >v[N][N],G[N];
int n,k,fa[N],sz[N],dp[N][N];
inline int readint(){
	char c=getchar();
	for(;!isdigit(c);c=getchar());
	int d=0;
	for(;isdigit(c);c=getchar())
	d=(d<<3)+(d<<1)+(c^‘0‘);
	return d;
}
void dfs(int now,int pre){
	sz[now]=1;
	for(int i=0,s=G[now].size();i<s;++i){
		int to=G[now][i].first;
		if(to!=pre){
			dfs(to,now);
			fa[to]=G[now][i].second;
			sz[now]+=sz[to];
		}
	}
}
void dfs2(int now,int pre){
	if(now==1)dp[now][sz[now]]=0;else{
		dp[now][sz[now]]=1;
		v[now][sz[now]].clear();
		v[now][sz[now]].push_back(make_pair(now,sz[now]));
	}
	dp[now][0]=0;
	for(int i=0,s=G[now].size();i<s;++i){
		int to=G[now][i].first;
		if(to!=pre){
			dfs2(to,now);
			for(int j=sz[now];j;--j)
			for(int k=0;k<=sz[to]&&k<=j;++k)
			if(dp[now][j]>dp[to][k]+dp[now][j-k]){
				dp[now][j]=dp[to][k]+dp[now][j-k];
				v[now][j]=v[now][j-k];
				v[now][j].push_back(make_pair(to,k));
			}
		}
	}
}
void print(int now,int p){
	if(sz[now]==p){
		printf("%d ",fa[now]);
		return;
	}
	for(int i=0,s=v[now][p].size();i<s;++i)
	print(v[now][p][i].first,v[now][p][i].second);
}
int main(){
	n=readint(),k=readint();
	for(int i=1;i<n;++i){
		int x=readint(),y=readint();
		G[x].push_back(make_pair(y,i));
		G[y].push_back(make_pair(x,i));
	}
	memset(dp,0x3f,sizeof dp);
	fa[1]=0;
	dfs(1,0);
	dfs2(1,0);
	int ans=dp[1][n-k],rt=1;
	for(int i=2;i<=n;++i)
	if(sz[i]>=k&&dp[i][sz[i]-k]+1<ans){
		ans=dp[i][sz[i]-k]+1;
		rt=i;
	}
	printf("%d\n",ans);
	if(rt!=1)printf("%d ",fa[rt]);
	print(rt,sz[rt]-k);
	return 0;
}

[Codeforces 440D]Berland Federalization

标签:turn   个数   for   make   pre   ret   pair   line   复杂   

原文地址:https://www.cnblogs.com/Mrsrz/p/8157891.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!