• [Codeforces 440D]Berland Federalization


    题目大意:给你一棵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
    ",ans);
    	if(rt!=1)printf("%d ",fa[rt]);
    	print(rt,sz[rt]-k);
    	return 0;
    }
  • 相关阅读:
    安装mysql
    date, Calendar
    心态
    jdbc ---- DBUTilDao 类
    jdbc--------JdbcUtilDao 类
    Python与C/C++相互调用
    用链表和数组实现HASH表,几种碰撞冲突解决方法
    用链表实现消息队列
    文件系统的发展
    [深度学习]开源的深度学习框架
  • 原文地址:https://www.cnblogs.com/Mrsrz/p/8157891.html
Copyright © 2020-2023  润新知