题意:N个点的一颗树。问最少添加多少条边可以让每个点都在一个(且仅一个)环中。

不得不佩服,这题dp设计出来的人。。。偶是弱菜,只能膜拜了。

这位大牛的解说,很详细:http://hi.baidu.com/19930705cxjff/blog/item/1df66e4a4ff3022e08f7ef5d.html

首先明确一点,题中的环至少需要3个顶点。因此,对于树中的每个顶点,有3种状态。
f[x][0]表示以x为根的树,变成每个顶点恰好在一个环中的图,需要连的最少边数。
f[x][1]表示以x为根的树,除了根x以外,其余顶点变成每个顶点恰好在一个环中的图,需要连的最少边数。
f[x][2]表示以x为根的树,除了根x以及和根相连的一条链(算上根一共至少2个顶点)以外,其余顶点变成每个顶点恰好在一个环中的图,需要连的最少边数。
有四种状态转移(假设正在考虑的顶点是R,有k个儿子):
A.根R的所有子树自己解决(取状态0),转移到R的状态1。即R所有的儿子都变成每个顶点恰好在一个环中的图,R自己不变。

B.根R的k-1个棵树自己解决,剩下一棵子树取状态1和状态2的最小值,转移到R的状态2。剩下的那棵子树和根R就构成了长度至少为2的一条链。

C.根R的k-2棵子树自己解决,剩下两棵子树取状态1和状态2的最小值,在这两棵子树之间连一条边,转移到R的状态0。

D.根R的k-1棵子树自己解决,剩下一棵子树取状态2(子树里还剩下长度至少为2的一条链),在这棵子树和根之间连一条边,构成一个环,转移到R的状态0。

ps:写代码要有胆量,不要怕TLE。。。直接暴力枚举这些值就行。

附代码:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <vector>
#include <cstring>
#include <algorithm>
#include <string>
#include <set>
#include <ctime>
#include <queue>
#include <map>
#include <sstream>#define CL(arr, val)    memset(arr, (val), sizeof(arr))
#define REP(i, n)       for((i) = 0; (i) < (n); ++(i))
#define FOR(i, l, h)    for((i) = (l); (i) <= (h); ++(i))
#define FORD(i, h, l)   for((i) = (h); (i) >= (l); --(i))
#define L(x)    (x) << 1
#define R(x)    (x) << 1 | 1
#define MID(l, r)   ((l) + (r)) >> 1
#define Min(x, y)   (x) < (y) ? (x) : (y)
#define Max(x, y)   (x) < (y) ? (y) : (x)
#define E(x)    (1 << (x))
#define iabs(x)  ((x) > 0 ? (x) : -(x))typedef long long LL;
const double eps = 1e-12;
const int inf = 10000;  using namespace std;const int N = 110;struct node {int to;int next;
} g[N<<2];    int head[N], t;bool vis[N];
int f[N][3];void init() {CL(head, -1); t = 0;
}void add(int u, int v) {g[t].to = v; g[t].next = head[u]; head[u] = t++;
}void dfs(int t) {int i, j, k, v, sum = 0, tmp, n;vector<int> ch;for(i = head[t]; i != -1; i = g[i].next) {v = g[i].to;if(!vis[v]) {vis[v] = true;dfs(v);sum += f[v][0];ch.push_back(v);}}n = ch.size();if(n == 0) {//printf("%d here!\n", t);f[t][0] = inf;f[t][1] = 0;f[t][2] = inf;return ;}f[t][1] = min(inf, sum);f[t][0] = f[t][2] = inf;for(i = 0; i < n; ++i) {v = ch[i];f[t][2] = min(f[t][2], sum - f[v][0] + min(f[v][1], f[v][2]));f[t][0] = min(f[t][0], sum - f[v][0] + f[v][2] + 1);}for(i = 0; i < n; ++i) {v = ch[i];for(j = 0; j < n; ++j) {if(i == j)  continue;k = ch[j];tmp = sum - f[v][0] - f[k][0] + min(f[v][1], f[v][2]) + min(f[k][1], f[k][2]);f[t][0] = min(f[t][0], tmp + 1);}}
}int main() {//freopen("data.in", "r", stdin);int n, x, y, i;while(~scanf("%d", &n)) {init();for(i = 1; i < n; ++i) {scanf("%d%d", &x, &y);add(x, y); add(y, x);}CL(vis, false); vis[1] = true;dfs(1);//for(i = 1; i <= n; ++i) printf("%d | %-11d %-11d %-11d\n", i, f[i][0], f[i][1], f[i][2]);if(f[1][0] >= inf)  puts("-1");else    printf("%d\n", f[1][0]);}return 0;
}

转载于:https://www.cnblogs.com/vongang/archive/2012/08/12/2634763.html

POJ 1848 (一道不错的树形dp)相关推荐

  1. POJ 1155 TELE【树形DP】

    POJ 1155 TELE http://poj.org/problem?id=1155 大意:某电台要广播一场比赛,该电台网络是由N个网点组成的一棵树,其中M个点为客户端, 其余点为转发站.客户端i ...

  2. POJ 1155 TELE 背包型树形DP 经典题

    由电视台,中转站,和用户的电视组成的体系刚好是一棵树 n个节点,编号分别为1~n,1是电视台中心,2~n-m是中转站,n-m+1~n是用户,1为root 现在节点1准备转播一场比赛,已知从一个节点传送 ...

  3. POJ - 3342 Party at Hali-Bula(树形dp)

    题目链接:点击查看 题目大意:n个人参加聚会,每个人都不想和老板一起参加,问最多可以有多少个人参加,并且判断方案唯一性 题目分析:这个类型的题目这已经是第三个了,状态转移方程都一模一样,不过这个题有点 ...

  4. HDU4008 Parent and son [树形DP]

    给定一棵树,求出当x为根时y的最小儿子和最小后代各是多少. 一道中等的树形DP,首先以1为根进行DP可以求出每个节点的最小儿子和最小后代.只有当x为y的孩子时才需要讨论,否则直接输出前面DP的结果即可 ...

  5. Fire (poj 2152 树形dp)

    Fire (poj 2152 树形dp) 给定一棵n个结点的树(1<n<=1000).现在要选择某些点,使得整棵树都被覆盖到.当选择第i个点的时候,可以覆盖和它距离在d[i]之内的结点,同 ...

  6. POJ - 2342 Anniversary party(树形dp入门)

    题目链接:点击查看 题目大意:每个人都有一个快乐值,给定一个树状的从属关系,仅当上司和下属都不在的时候这个个人的快乐值才能表现出来,问怎么样才能让整体的快乐值达到最大 题目分析:做线段树做吐了,来换换 ...

  7. C++剑指offer:[POJ]2631 Roads in the North - 用树形DP的方式求出一棵树的直径

    前言 此题是道很简单的题(做法不单一,不仅只有树形DP的方法) 做完了这道题才发现此题原来是一道求树的直径的题,也就是求树上两个节点的最大距离. 题目 问题 N(2692): [POJ2631]北极地 ...

  8. POJ 2342 | HDU 1520 Anniversary party 树形DP(入门题)

    传送门:POJ 2342 题目大意: 有若干人参加一个聚会,如果两个人之间有直接的上下属关系,则只能去一个.每个人都有个高兴值,问高兴值之和最大是多少? 思路: 之前一直觉得树形DP比较难,现在发现树 ...

  9. POJ 3342 树形DP+Hash

    这是很久很久以前做的一道题,可惜当时WA了一页以后放弃了. 今天我又重新捡了起来.(哈哈1A了) 题意: 没有上司的舞会+判重 思路: hash一下+树形DP 题目中给的人名hash到数字,再进行运算 ...

最新文章

  1. 对IsUnderPostmaster变量初步学习
  2. 【转载】word2vec 中的数学原理详解
  3. Access数据库查询练习专用数据库 -手机号码归属地Access数据库_MobileDB(10万条记录)...
  4. 基于CLGeocoder - 地理编码
  5. C# ASP.NET MVC 配置允许跨域访问
  6. RestTemplate实践
  7. Numpy中tile函数的用法
  8. 修改Win7远程桌面端口
  9. Linux记录-重启后磁盘丢失问题解决方案
  10. SVN Description : The working copy is locked due to a previous error.
  11. 关于判断卡BIN的修正
  12. Base64基本原理及简单应用
  13. 考研计算机专业课961考什么,北航计算机考研(961)经验谈
  14. 智能网联(车联网)示范区发展现状分析—华南篇
  15. 服务过载保护设计与实施
  16. 电脑图片格式怎么批量转换jpg?几个小妙招轻松转换
  17. RabbitMQ 中的 VirtualHost 该如何理解
  18. 嘉和美康科创板IPO:阿里健康是股东,副总姬铮并非核心技术人员
  19. 调起安卓手机自带应用商店
  20. 最新版 FatFS f_mkfs 详解

热门文章

  1. 小型电梯尺寸_简易式家用电梯-潞城=小型阁楼家用电梯
  2. linux运维必学python吗_linux运维一定要学python吗?
  3. python编程高手教程_写给编程高手的Python教程(11) 深入类和对象
  4. 020_泛型变量的类型限定
  5. 008_logback配置语法
  6. 垃圾回收在哪一章java_Java垃圾回收机制
  7. java中ArrayList与LinkedList的区别
  8. sql left join用法_一张图看懂 SQL 的各种 join 用法
  9. kali怎么新建文本_甘特图怎么画?零基础快速绘制甘特图的软件
  10. Android数据存储与持久化