题目链接:http://poj.org/problem?id=1947

Rebuilding Roads
Time Limit: 1000MS   Memory Limit: 30000K
Total Submissions: 13501   Accepted: 6253

Description

The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1..N) after the terrible earthquake last May. The cows didn't have time to rebuild any extra roads, so now there is exactly one way to get from any given barn to any other barn. Thus, the farm transportation system can be represented as a tree.

Farmer John wants to know how much damage another earthquake could do. He wants to know the minimum number of roads whose destruction would isolate a subtree of exactly P (1 <= P <= N) barns from the rest of the barns.

Input

* Line 1: Two integers, N and P

* Lines 2..N: N-1 lines, each with two integers I and J. Node I is node J's parent in the tree of roads.

Output

A single line containing the integer that is the minimum number of roads that need to be destroyed for a subtree of P nodes to be isolated. 

Sample Input

11 6
1 2
1 3
1 4
1 5
2 6
2 7
2 8
4 9
4 10
4 11

Sample Output

2

Hint

[A subtree with nodes (1, 2, 3, 6, 7, 8) will become isolated if roads 1-4 and 1-5 are destroyed.] 
 
题意:给你一颗有n个节点的树,问你最少去掉多少条边可以得到节点数m的子树
思路:一开始没认真看题目,以为题目是问从树上取出m个节点最少要多少条边(取出的节点可以不相连),然后就wa了。。。
看到这题,就很容易想出dp数组,dp[i][j]表示从以i为根节点 的子树中去点j个节点最少要去掉的边数
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct{//链式前向星
int v,next;
}edge[];
int head[];
int dp[][];//dp[i][j]表示在i节点的子树里(不是以i组成的子树)去掉j个节点需要减少的最少的边数
int sum[];//sum[i]表示在i节点的子树里一个有多少个节点(不包括i)
int cnt;
void add(int u,int v){
edge[cnt].v=v;
edge[cnt].next=head[u];
head[u]=cnt++;
}
/*
i节点的子树(不包括i)
以i节点为根组成子树(树)(包括i)
*/
int n,m;
void dfs(int k){
sum[k]=;//初始化
for(int i=;i<=n;i++)//初始化
dp[k][i]=1e9;
dp[k][]=;//无论是哪个点,去掉0个节点的花费一定是0
for(int i=head[k];i!=-;i=edge[i].next){
dfs(edge[i].v);//先向子节点搜索
sum[k]+=sum[edge[i].v]+;//计算k节点的子树里有多少个节点
dp[edge[i].v][sum[edge[i].v]+]=;//去除当前子节点为根组成树的所有的节点的花费一定是1(只需断开k与当前子节点的连接)
//printf("%d %d %d\n",edge[i].v,sum[edge[i].v]+1,dp[edge[i].v][sum[edge[i].v]+1]) ;
for(int j=n;j>;j--){ //为什么要j>0,因为j=0的花费一定是0,没必要更新
for(int l=;l<=j;l++)
dp[k][j]=min(dp[k][j],dp[k][j-l]+dp[edge[i].v][l]);
/*为什么l从1开始,因为从0开始没必要(min(dp[k][j],dp[k][j]+dp[edge[i].v][0]);)它的
结果一定是原来的dp[k][j],因为 dp[edge[i].v][0]=0,为什么l可以等于j,因为我可以当前的j个全部
从当前子节点组成的子树去除*/
}
}
}
bool vt[];//标记数组
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
int u,v;
cnt=;
fill(head,head+,false);//初始化
fill(head,head+,-);
for(int i=;i<n;i++){
scanf("%d%d",&u,&v);
add(u,v);
vt[v]=true;
}
int root=;
for(int i=;i<=n&&!root;i++){//找根节点
if(!vt[i])
root=i;
}
dfs(root);
int ans=dp[root][n-m];//我要得到节点数为m的子树,需要去掉n-m个点
for(int i=;i<=n;i++)
if(sum[i]+>=m)
ans=min(ans,dp[i][sum[i]+-m]+);//取以第i个节点为根节点组成的子树(包括i)时,先要减去他与父节点的连接,
//然后再到子树里减去sum[i]+1-m个节点(因为以i为根组成的子树(树)只有sum[i]+1个节点)
printf("%d\n",ans);
} return ;
}

绿色的表示以2节点为根节点组成的子树

红色的表示2节点的子树

poj1947(树形背包)的更多相关文章

  1. poj2486Apple Tree[树形背包!!!]

    Apple Tree Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 9989   Accepted: 3324 Descri ...

  2. cdoj 1136 邱老师玩游戏 树形背包

    邱老师玩游戏 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1136 Desc ...

  3. HDU 1011 树形背包(DP) Starship Troopers

    题目链接:  HDU 1011 树形背包(DP) Starship Troopers 题意:  地图中有一些房间, 每个房间有一定的bugs和得到brains的可能性值, 一个人带领m支军队从入口(房 ...

  4. poj 1155 TELE (树形背包dp)

    本文出自   http://blog.csdn.net/shuangde800 题目链接: poj-1155 题意 某收费有线电视网计划转播一场重要的足球比赛.他们的转播网和用户终端构成一棵树状结构, ...

  5. bzoj 4813: [Cqoi2017]小Q的棋盘 [树形背包dp]

    4813: [Cqoi2017]小Q的棋盘 题意: 某poj弱化版?树形背包 据说还可以贪心... #include <iostream> #include <cstdio> ...

  6. [HAOI2015]树上染色(树形背包)

    有一棵点数为 N 的树,树边有边权.给你一个在 0~ N 之内的正整数 K ,你要在这棵树中选择 K个点,将其染成黑色,并将其他 的N-K个点染成白色 . 将所有点染色后,你会获得黑点两两之间的距离加 ...

  7. Luogu 1273 有线电视网 - 树形背包

    Description 树形背包, 遍历到一个节点, 枚举它的每个子节点要选择多少个用户进行转移. Code #include<cstring> #include<cstdio> ...

  8. BZOJ2427: [HAOI2010]软件安装 tarjan+树形背包

    分析: 一开始我以为是裸的树形背包...之后被告知这东西...可能有环...什么!有环! 有环就搞掉就就可以了...tarjan缩点...建图记得建立从i到d[i]之后跑tarjan,因为这样才能判断 ...

  9. [Jsoi2016]最佳团体 BZOJ4753 01分数规划+树形背包/dfs序

    分析: 化简一下我们可以发现,suma*ans=sumb,那么我们考虑二分ans,之后做树形背包上做剪枝. 时间复杂度证明,By GXZlegend O(nklogans) 附上代码: #includ ...

  10. BZOJ 2427 [HAOI2010]软件安装 | 这道树形背包裸题严谨地证明了我的菜

    传送门 BZOJ 2427 题解 Tarjan把环缩成点,然后跑树形背包即可. 我用的树形背包是DFS序上搞的那种. 要注意dp数组初始化成-INF! 要注意dp顺推的时候也不要忘记看数组是否越界! ...

随机推荐

  1. leetcode算法题01

    最近求职需要重新刷算法题,从今天开始每天至少做一个leatcode的题 如果有更好的算法或者换了语言也会更新 题目: 给定一个整数数组和一个目标值,找出数组中和为目标值的两个数. 你可以假设每个输入只 ...

  2. python2和python3的range(100)的区别

    python2返回列表,python3返回迭代器,节约内存

  3. curl的POST请求,封装方法

    //POST请求//参数1是请求的url//参数2是发送的数据的数组//参数3是其他POST选项public static function POST($url, array $post = arra ...

  4. Asp.net core 学习笔记 Razor Page

    更新 2019-04-27 最近做了更多的 research 发现微软视乎有意发展 razor page. razor page 的定位是 mvvm, 现在还有个叫 blazor 的东西, 类似用 c ...

  5. java中循环遍历实体类的属性和数据类型以及属性值

    package com.walkerjava.test; import java.lang.reflect.Field; import java.lang.reflect.InvocationTarg ...

  6. 记一次oracle数据库复制过程

    记录一次自己数据库复制的过程(从公司测试环境复制到客户测试环境),主要是每次自己都会忘记,不如记录一下,方便自己以后找,因此,本篇内容不会很详细,主要是用于给我自己提醒,相对于一种记笔记的效果. cm ...

  7. svn 的权限配置

    #分配用户所属组 g_admin=admin g_ui=zhangsan,lisi g_code=wangwu g_test=zhaoliu,qianqi #分配目录权限 #表示项目根目录 [/] @ ...

  8. 关于lower_bound( )和upper_bound( )的常见用法

    lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的. 在从小到大的排序数组中, lower_bound( begin,end,num):从数 ...

  9. Letters Removing CodeForces - 899F (线段树维护序列)

    大意: 给定字符串, 每次删除一段区间的某种字符, 最后输出序列. 类似于splay维护序列. 每次删除都会影响到后面字符的位置 可以通过转化为查询前缀和=k来查找下标. #include <i ...

  10. git reset 和 git revert 使用区别

    git reset 用于回退代码,但是git pull后会和远程分支保持一致,所以无法修改远程代码 git revert可以撤销代码,撤销后直接git push ,可以修改远程分支的代码