题目大意:

根据两个点建立一条有向边,最后可形成的是一棵树,希望通过切除一些边,使一棵含有p个节点的子树被独立出来,希望切除的边数最少,输出这个边数

这个是第一次自己完完整整做出来的树形Dp题目,没有参考别人的DP思路,虽然自己很快想好了,但是总是无法合适的进行组织,做了很久,但自己做出来的

总是会比取理解别人代码来的效果好很多

用dp[u][j] 记录u号节点这棵子树中含有j个点需要砍去的最少的边数

两次dfs , 第一次dfs查出对应节点的下方子树中一共有多少个节点,顺便记录一个节点在当前延伸出去了几条边

也就是dp[u][1] ,表示最后u代表的子树下方全部砍去只剩u这一个点

第二次dfs中自底向上不断将子树添加进来,根据dp值判断是否适合加入这个子树,如果适合加入,那么因为之前砍去的那条边要加回来,所以

砍去的边要少一

dp[u][j] = min(dp[u][j] , dp[v][k] + dp[u][j-k] - 1) k<j

这里判断dp[u][j] , 和dp[v][k] + dp[u][j-k] - 1的大小,前一个表示没必要添加v子树,后一个表示添加了v子树效果更好

实际这里的二重循环也是相当于类似背包问题的思想

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <iostream>
 4
 5 using namespace std;
 6 const int INF = 0x3f3f3f3f;
 7 const int N = 205;
 8
 9 int dp[N][N] , sum[N] , first[N] , col[N] , root , k;
10
11 struct Edge{
12     int y , next;
13 }e[N];
14
15 void add_edge(int x , int y)
16 {
17     e[k].y = y  , e[k].next = first[x];
18     first[x] = k++;
19 }
20
21 void dfs1(int u)
22 {
23     sum[u] = 1;
24     dp[u][1] = 0;
25     for(int i=first[u] ; i!=-1 ; i=e[i].next){
26         dp[u][1] ++;
27         int v = e[i].y;
28         dfs1(v);
29         sum[u] += sum[v];
30     }
31 }
32
33 void dfs2(int u , int n)
34 {
35     dp[u][sum[u]] = 0;
36     for(int i=first[u] ; i!=-1 ; i=e[i].next){
37         int v = e[i].y;
38         dfs2(v , n);
39         //这里j必须递减,因为运算中用到了dp[u][j-k],如果是递增顺序,那么会提前把要使用的更新了
40         for(int j=sum[u] ; j>=2 ; j--){
41             for(int k=j-1 ; k>=1 ; k--){
42                 dp[u][j] = min(dp[u][j] , dp[v][k] + dp[u][j-k] - 1);
43             }
44         }
45     }
46 }
47
48 int main()
49 {
50    // freopen("a.in" , "r" , stdin);
51     int n , p , a , b;
52     while(scanf("%d%d" , &n , &p) == 2)
53     {
54         memset(first , -1 , sizeof(first));
55         memset(col , 0 , sizeof(col));
56         k = 0;
57         for(int i=1 ; i<n ; i++){
58             scanf("%d%d" , &a , &b);
59             add_edge(a , b);
60             col[b] = 1;
61         }
62         for(int i = 1 ; i<=n ; i++)
63             if(!col[i]) root = i;
64
65         memset(dp , 0x3f , sizeof(dp));
66         dfs1(root);
67         dfs2(root , n);
68
69         int minn = INF;
70         for(int i=1 ; i<=n ; i++){
71             if(i == root) minn = min(minn , dp[i][p]);
72             else minn = min(minn , dp[i][p]+1);
73         }
74         printf("%d\n" , minn);
75     }
76     return 0;
77 }

转载于:https://www.cnblogs.com/CSU3901130321/p/4232375.html

POJ 1947 Rebuilding Roads相关推荐

  1. POJ 1947 Rebuilding Roads (树dp + 背包思想)

    题目链接:http://poj.org/problem?id=1947 一共有n个节点,要求减去最少的边,行号剩下p个节点.问你去掉的最少边数. dp[u][j]表示u为子树根,且得到j个节点最少减去 ...

  2. HDU 1815, POJ 2749 Building roads(2-sat)

    HDU 1815, POJ 2749 Building roads 题目链接HDU 题目链接POJ 题意: 有n个牛棚, 还有两个中转站S1和S2, S1和S2用一条路连接起来. 为了使得随意牛棚两个 ...

  3. 【POJ - 1947】Rebuilding Roads (树形dp,背包问题,树形背包dp)

    题干: The cows have reconstructed Farmer John's farm, with its N barns (1 <= N <= 150, number 1. ...

  4. 【POJ - 1724 】ROADS (带限制的最短路 或 dfs 或 A*算法,双权值)

    题干: N cities named with numbers 1 ... N are connected with one-way roads. Each road has two paramete ...

  5. POJ 1251 Jungle Roads

    题意:给你n个点  n-1行每行代表的是这个点到给定点的距离   求最短路 解题思路:开始是用getchar  发现runtime error   后来用了  字符串  才改进了   裸Kruskal ...

  6. 【POJ - 2631】Roads in the North (树的直径,模板)

    题干: Building and maintaining roads among communities in the far North is an expensive business. With ...

  7. 【POJ - 2631 】Roads in the North(树的直径)

    题干: Building and maintaining roads among communities in the far North is an expensive business. With ...

  8. POJ 2749 Building roads 2-sat+二分答案

    把爱恨和最大距离视为限制条件,可以知道,最大距离和限制条件多少具有单调性 所以可以二分最大距离,加边+check 1 #include<cstdio> 2 #include<algo ...

  9. POJ 2749 Building roads

    POJ_2749 一开始没有想到去二分距离,看了别人的报告之后恍然大悟. 这是一个2-SAT的问题,首先我们要去找到核心变量,可以看出每个牛的有着要么和S1相连,要么和S2相连的逻辑关系,因此可以把奶 ...

  10. poj 1947(树形dp+背包问题)

    题大意是:给你一棵节点为n的树,问至少砍几刀可以孤立出一棵节点为m的子树. 解题思路:这题很容易想到状态dp[i][j]表示以i节点为根,节点总数为j的子树最少需要切几刀.但是这个状态方程确实很难想, ...

最新文章

  1. 20162329 2017-2018-1 《程序设计与数据结构》第十一周学习总结
  2. 0. 正规鞅的混沌及可料表示
  3. ASP.NET缓存之 没有为 SQL 缓存通知启用数据库“ReplaceShop”。
  4. python进程监控及恢复
  5. python 运算符重载_Python3面向对象-运算符重载
  6. CentOS 7 Apache服务的安装与配置(转)
  7. SpringBoot—Entity父子类表@Inheritance和@MappedSuperclass
  8. 《信息通信技术与政策》丨盖国强:中国数据库服务生态与体系
  9. Rsync安装与配置
  10. Linux系统调用过程(Linux0.11内核实验)
  11. 没有事业的女人会很惨
  12. python可以下载百度文库_python+selenium爬取百度文库不能下载的word文档
  13. URLOS实战入门—制作LAP网站环境
  14. Android 6.0 Marshmallow介绍
  15. SQL注入之二次注入
  16. 假设一个录像厅有0,1,2三种不同的录像片可由观众选择放映。录像厅的放映规则为: 1)任何时刻最多只能放映一种录像片,正在放映的录像片是自动循环放映的。最后一个观众主动离开时结束当前录像片的放映。
  17. 读1973年的弹子球有感。_北国的雪_新浪博客
  18. windows通过双网卡双网络(本地网卡和无线网卡双网络同时工作)
  19. 《长三角区域大数据发展报告(2018)》在杭发布
  20. linux怎样在根目录下创建文件夹

热门文章

  1. 实际测试中,经常发现摄像头断线几分钟
  2. error while loading shared libraries: libxx.so: cannot open shared object file: No such file
  3. 创业失败反思:市场跟销售完全是两回事
  4. UBUNTU给已有用户改名
  5. 管理感悟:区分话的难听与对错
  6. mysql中regexp用法_MySQL中REGEXP正则表达式使用大全
  7. php 类似百度分页,写了一个仿百度贴吧分页效果的分页类,有人要么?
  8. kafka php 教程,php 使用kafka
  9. android av和hdmi输出切换代码,AV转HDMI转换器有用吗?
  10. 多个路由指向同一个页面_ASP.NET实战008:MVC路由实现详解