zoukankan      html  css  js  c++  java
  • 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;
    }
    

      

  • 相关阅读:
    centos 编程环境
    git 安装 使用
    nodejs 笔记
    微信开发
    composer 使用笔记
    一:安装centos 7最小编程环境 xfce桌面
    二: 安装centos服务环境软件mysql httpd php
    我的通用程序规范及说明
    常用js代码集
    三 , lnmp 一键包安装使用
  • 原文地址:https://www.cnblogs.com/20143605--pcx/p/5348610.html
Copyright © 2011-2022 走看看