• POJ-1947 Rebuilding Roads (树形DP+分组背包)


    题目大意:将一棵n个节点的有根树,删掉一些边变成恰有m个节点的新树。求最少需要去掉几条边。

    题目分析:定义状态dp(root,k)表示在以root为根节点的子树中,删掉一些边变成恰有k个节点的新树需要删去的最少边数。对于根节点root的某个儿子son,要么将son及其所有的子节点全部删掉,则dp(root,k)=dp(root,k)+1,只需删除root与son之间的边;要么在son的子树中选出一些边删掉,构造出有j个节点的子树,状态转移方程为dp(root,k)=max(dp(root,k),dp(son,j)+dp(root,k-j))。

    代码如下:

    # include<iostream>
    # include<cstdio>
    # include<cstring>
    # include<vector>
    # include<algorithm>
    using namespace std;
    
    const int N=155;
    const int INF=1000000000;
    
    int n,m;
    bool flag[N];
    int dp[N][N];
    vector<int>e[N];
    
    void init()
    {
    	int a,b;
    	for(int i=1;i<=n;++i){
    		e[i].clear();
    		for(int j=0;j<=m;++j)
    			dp[i][j]=INF;
    	}
    	memset(flag,false,sizeof(flag));
    	for(int i=1;i<n;++i){
    		scanf("%d%d",&a,&b);
    		e[a].push_back(b);
    		flag[b]=true;
    	}
    }
    
    void dfs(int u)
    {
    	dp[u][1]=0;
    	for(int i=0;i<e[u].size();++i){
    		int v=e[u][i];
    		dfs(v);
    		for(int j=m;j>=1;--j){
    			dp[u][j]+=1;
    			for(int k=1;k<j;++k){	///k从1循环到j-1,一定不能从0循环到j
    				dp[u][j]=min(dp[u][j],dp[v][k]+dp[u][j-k]);
    			}
    		}
    	}
    }
    
    void solve()
    {
    	int ans=INF;
    	for(int i=1;i<=n;++i){
    		if(flag[i]) continue;
    		dfs(i);
    		ans=dp[i][m];
    		break;
    	}
    	for(int i=1;i<=n;++i)
    		ans=min(ans,dp[i][m]+1);
    	printf("%d
    ",ans);
    }
    
    int main()
    {
    	while(~scanf("%d%d",&n,&m))
    	{
    		init();
    		solve();
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    IE浏览器中js使用中文标识符的bug
    Javascript变量作用域
    利用JS的动态语言特性对数组排序
    Javascript动态方法调用与参数修改的问题
    数组的平衡点
    Javascript中各种trim的实现
    js對象的比較
    返回两个数组中非相同的元素
    Javascript中匿名函数的多种调用方式
    SQL Server PreLogin Handshake Acknowledgement Error [duplicate]
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5348610.html
Copyright © 2020-2023  润新知