zoukankan      html  css  js  c++  java
  • P1272 重建道路 | 树上背包

    题目描述

    从一棵树上选择数量最少的边断开 使得拆出的子树大小为P

    题解

    树上dp
    (f[i][j]) 表示子树i中拆分出j个节点 需要最少删去多少边
    考虑树上背包的模板 我们对于一个节点now
    合并时候 把该节点的每个子树看成一个组 子树中每一个点看成物品进行分组背包
    由于每个非根节点想要单独拆分出来,所以答案要+1
    最后,由于拆分并不需要在根节点进行
    所以对于每个节点都可以看一看有没有更优秀的答案
    code:

    #include<bits/stdc++.h>
    #define ll long long
    #define inf 0x3f3f3f3f
    using namespace std;
    #define maxn 159
    int n,p;
    int f[maxn][maxn];
    vector<int> son[maxn];
    int dfs(int now,int fa)//返回子树个数 
    {
    	f[now][1]=0;
    	int size=1;
    	for(int i=0;i<son[now].size();i++)
    	{
    		int to=son[now][i];
    		if(to==fa)continue;
    		int tk=dfs(to,now);
    		size+=tk;
    		for(int j=size;j>=0;j--)//分j组 
    		{
    			f[now][j]++;
    			for(int k=0;k<=min(tk,j-1);k++)//j-1强制选根 
    			{
    				f[now][j]=min(f[now][j],f[to][k]+f[now][j-k]);
    			}
    		}
    	}
    	return size;
    }
    signed main()
    {
    	scanf("%d%d",&n,&p);
    	memset(f,0x3f,sizeof(f));
    	for(int i=1;i<n;i++)
    	{
    		int x,y;
    		scanf("%d%d",&x,&y);
    		son[x].push_back(y);
    		son[y].push_back(x);
    	}
    	dfs(1,0);
    	int ans=f[1][p];
    	for(int i=2;i<=n;i++)ans=min(ans,f[i][p]+1);
    	printf("%d
    ",ans);
    	return 0;
    }
    /*
    f[i][j]表示子树i中分离出j个节点需要多少道路 
    强制当前子树i和父节点相连 
    f[i][j]变成了 有s个物品 每个节点有 
    */
    ``
  • 相关阅读:
    MD5值算法原理
    AUTH过程
    锁定应用,解锁应用,锁卡,解卡,更改密码指令
    借/贷记卡的应用
    借记卡,贷记卡,准贷记卡三者的区别
    PBOC2.0与PBOC3.0的区别
    ED/EP简介
    与恒宝有关的一些常用知识
    java卡与native卡的区别
    计算机组和域的区别
  • 原文地址:https://www.cnblogs.com/lzy-blog/p/15294779.html
Copyright © 2011-2022 走看看