POJ 3659 Cell Phone Network / HUST 1036 Cell Phone Network(最小支配集,树型动态规划,贪心)

Description

Farmer John has decided to give each of his cows a cell phone in hopes to encourage their social interaction. This, however, requires him to set up cell phone towers on his N (1 ≤ N ≤ 10,000) pastures (conveniently numbered 1..N) so they can all communicate.

Exactly N-1 pairs of pastures are adjacent, and for any two pastures A and B (1 ≤ A ≤ N; 1 ≤ B ≤ N; A ≠ B) there is a sequence of adjacent pastures such that A is the first pasture in the sequence and B is the last. Farmer John can only place cell phone towers in the pastures, and each tower has enough range to provide service to the pasture it is on and all pastures adjacent to the pasture with the cell tower.

Help him determine the minimum number of towers he must install to provide cell phone service to each pasture.

Input

Line 1: A single integer: N

Lines 2..N: Each line specifies a pair of adjacent pastures with two space-separated integers: A and B

Output

Line 1: A single integer indicating the minimum number of towers to install

Sample Input

5

1 3

5 2

4 3

3 5

Sample Output

2

Http

POJ:https://vjudge.net/problem/POJ-3659

HUST:https://vjudge.net/problem/HUST-1036

Source

最小支配集,树型动态规划,贪心

题目大意

在一棵树上选出最小的点集,使得每个点都满足自己在集合中或相连的点在集合中(一下简称某点被覆盖/被选)

解决思路

这道题的贪心解法在这里,那么本文就讲一讲DP的做法。

首先我们观察,一个点被覆盖只有三种情况

1.被它自己覆盖

2.被它的儿子节点覆盖

3.被它的父亲覆盖

根据以上的分析,我们就可以令F[u][0],F[u][1],F[u][2]分别表示u在上述的三种情况能得到的最小值。接下来就是推导出动归方程啦!

先来看简单点的两种情况F[u][0]和F[u][2](下面我们均用v来代表u的子节点)

F[u][0]代表的是u点选择u点进行覆盖,那么经过推到我们可得

\[F[u][0]=\Sigma(max\begin{cases}F[v][0]\\F[v][1]\\F[v][2]\end{cases})
\]

而F[u][2]则代表的是u被其父节点覆盖,这同样也代表着u不是被选中的点,也就是说u的子节点v的F[v][2]不放入考虑范围(为什么?因为F[v][2]代表的是v被父节点也就是u覆盖啦,但u又不选),那么我们就有

\[F[u][2]=\Sigma(max\begin{cases}F[v][0]\\F[v][1]\end{cases})
\]

最后就是F[u][1]啦。它代表的是u节点被其子节点覆盖。

稍微缓一下,这里说的覆盖可以>=1个子节点哦!

那么对于F[u][1]来说,它可以从v的哪些状态得到呢?

经过简单的思考,我们得出F[u][1]可以从F[v][1]和F[v][0]得到(为什么不能是F[v][2]呢?前面已经讲过了,既然选择F[u][1]计算,也就意味着u点不被选择去覆盖别的点)。那难道动归方程是这样的吗?

\[F[u][1]=\Sigma(max\begin{cases}F[v][0]\\F[v][1]\end{cases})
\]

且住,这样不就和F[u][2]一样了吗

不知道读者有没有发现问题,这样写出的方程在转移时可能出现问题,那就是有可能出现在求和时每一个v都取的是F[v][1],这也就意味着我们最后求出来的F[u][1]代表的解中u的子节点v都没有被选择去覆盖别的点!!!,而这与我们对F[u][1]的定义是矛盾的。

怎么办呢?我们要用一个bool类型的变量flag来记录下F[u][1]是否从F[v][0]这种状态转移过来过,如果没有,则要强制让一个从F[v][1]转移过来的变成从F[v][0]转移过来,并且还要保证尽量小

最后的问题是,如何强制呢?我们令一个变量inc=min(F[v][0]-F[v][1]),那么如果最后检查flag标记时若发现F[u][1]没有从F[v][0]转移来的历史记录,我们就F[u][1]+=inc就可以啦(这就相当于强制让一个从F[v][1]转移过来的变成从F[v][0]转移过来,并保证了最小)

所以最后F[u][1]的状态转移方程就是

\[F[u][1]=\begin{cases}\Sigma min(F[v][0],F[v][1]) \text (如果u的子节点v中有被选择的) \\\Sigma min(F[v][0],F[v][1])+inc \text (如果u的子节点v中没有被选择的)\end{cases}
\]

\[inc=min(F[v][0]-F[v][1])
\]

最后的最后要注意的地方就是最后输出答案的时候是min(F[1][0],F[1][1]),而不是min(F[1][0],F[1][1],F[1][2])(你问我为什么,1就是根节点,哪里会被其“父节点”覆盖呢)

代码

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<algorithm>
  6. #include<vector>
  7. using namespace std;
  8. const int maxN=10001;
  9. const int inf=147483647;
  10. int n;
  11. vector<int> E[maxN];
  12. int F[maxN][5]={0};
  13. bool vis[maxN];
  14. void dfs(int u);
  15. int main()
  16. {
  17. cin>>n;
  18. for (int i=1;i<n;i++)
  19. {
  20. int x,y;
  21. cin>>x>>y;
  22. E[x].push_back(y);
  23. E[y].push_back(x);
  24. }
  25. memset(vis,0,sizeof(vis));
  26. dfs(1);
  27. cout<<min(F[1][0],F[1][1])<<endl;
  28. return 0;
  29. }
  30. void dfs(int u)
  31. {
  32. F[u][0]=1;
  33. F[u][2]=0;
  34. F[u][1]=0;
  35. vis[u]=1;
  36. bool flag=0;//标记u的子树中计算F[u][1]时是否取过F[v][0]
  37. int inc=inf;
  38. for (int i=0;i<E[u].size();i++)
  39. {
  40. int v=E[u][i];
  41. if (vis[v]==0)
  42. {
  43. dfs(v);
  44. F[u][0]+=min(F[v][0],min(F[v][1],F[v][2]));
  45. F[u][2]+=min(F[v][1],F[v][0]);
  46. if (F[v][0]<=F[v][1])//这里就是对F[u][1]的处理啦,另外注意这里要取等
  47. {
  48. flag=1;
  49. F[u][1]+=F[v][0];
  50. }
  51. else
  52. {
  53. inc=min(inc,(F[v][0]-F[v][1]));
  54. F[u][1]+=F[v][1];
  55. }
  56. }
  57. }
  58. if (flag==0)//若在计算F[u][1]时没有从F[v][0]推导过来的,就要强制将一个转换成从F[v][0]推导过来。
  59. {
  60. F[u][1]+=inc;
  61. }
  62. return;
  63. }

POJ 3659 Cell Phone Network / HUST 1036 Cell Phone Network(最小支配集,树型动态规划,贪心)-动态规划做法的更多相关文章

  1. POJ 3659 Cell Phone Network(树的最小支配集)(贪心)

    Cell Phone Network Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 6781   Accepted: 242 ...

  2. poj-3659 Cell Phone Network(最小支配集+贪心)

    http://poj.org/problem?id=3659 Description Farmer John has decided to give each of his cows a cell p ...

  3. POJ 3398 Perfect Service(树型动态规划,最小支配集)

    POJ 3398 Perfect Service(树型动态规划,最小支配集) Description A network is composed of N computers connected by ...

  4. POJ 3398 Perfect Service --最小支配集

    题目链接:http://poj.org/problem?id=3398 这题可以用两种上述讲的两种算法解:http://www.cnblogs.com/whatbeg/p/3776612.html 第 ...

  5. POJ 2342 Anniversary party / HDU 1520 Anniversary party / URAL 1039 Anniversary party(树型动态规划)

    POJ 2342 Anniversary party / HDU 1520 Anniversary party / URAL 1039 Anniversary party(树型动态规划) Descri ...

  6. 树的最小支配集 E - Cell Phone Network POJ - 3659 E. Tree with Small Distances

    E - Cell Phone Network POJ - 3659 题目大意: 给你一棵树,放置灯塔,每一个节点可以覆盖的范围是这个节点的所有子节点和他的父亲节点,问要使得所有的节点被覆盖的最少灯塔数 ...

  7. POJ 3659 Cell Phone Network 最小支配集模板题(树形dp)

    题意:有以个 有 N 个节点的树形地图,问在这些顶点上最少建多少个电话杆,可以使得所有顶点被覆盖到,一个节点如果建立了电话杆,那么和它直接相连的顶点也会被覆盖到. 分析:用最少的点覆盖所有的点,即为求 ...

  8. POJ3659 Cell Phone Network(树上最小支配集:树型DP)

    题目求一棵树的最小支配数. 支配集,即把图的点分成两个集合,所有非支配集内的点都和支配集内的某一点相邻. 听说即使是二分图,最小支配集的求解也是还没多项式算法的.而树上求最小支配集树型DP就OK了. ...

  9. POJ 2152 fire / SCU 2977 fire(树型动态规划)

    POJ 2152 fire / SCU 2977 fire(树型动态规划) Description Country Z has N cities, which are numbered from 1 ...

随机推荐

  1. 并行类加载与OSGI类加载

    这回来分析一下OSGI的类加载机制. 先说一下OSGI能解决什么问题吧. 记得在上家公司的时候,经常参与上线.上线一般都是增加了一些功能或者修改了一些功能,然后将所有的代码重新部署.过程中要将之前的服 ...

  2. 03 编译安装apache的简易配置

    1.监听端口,默认为80,在主配置文件 /etc/httpd24/httpd.conf中可以更改 2.持久连接 Include /etc/httpd24/extra/httpd-default.con ...

  3. sqlserver删除重复的数据

    分享链接: http://blog.csdn.net/s630730701/article/details/52033018 http://blog.csdn.net/anya/article/det ...

  4. 前端向后台的华丽转身 — PHP基础篇

    这一次,本K带大家来看一下关于PHP中数组.字符串的一些注意事项和函数(方法). 一.PHP中的数组 (一)PHP中的数组简介 数组类型是PHP两种复合数据类型之一.根据下标的不同,可以将PHP中的数 ...

  5. 构建自己的PHP框架--构建模版引擎(2)

    自从来到新公司就一直很忙,最近这段时间终于稍微闲了一点,赶紧接着写这个系列,感觉再不写就烂尾了. 之前我们说到,拿到{{ $name }}这样一段内容时,我们只需要将它转化成<?php echo ...

  6. 关于Dubbo分布式服务

    这篇文章写的详细,可参考 http://shiyanjun.cn/archives/1075.html

  7. APUE-文件和目录(七)符号链接

    符号链接 符号链接的用途 符号链接是对一个文件的间接指针,它与前面介绍的硬连接不同,硬连接指向文件的i节点.引入符号链接是为了避开硬连接的一些限制: 硬链接通常要求链接和文件位于同一文件系统中. 只有 ...

  8. /dev/shm 与 tmpfs

    1./dev/shm 与 tmpfs /dev/shm/是linux下一个目录,/dev/shm目录不在磁盘上,而是在内存里, 类型为 tmpfs ,因此使用linux /dev/shm/ 的效率非常 ...

  9. Oracle数据库概念和一些基本的SQL语句

    1.数据 定义:描述事物的符号.例如:文本.音频.视频都是数据. 2.数据库 存放数据的仓库,存放在计算机中,按照一定格式存放,可以为用户共享. 3.数据库的发展阶段 1.网状数据库 2.层次数据库 ...

  10. jquery hide和show使用

    $("#qitarenyuanDiv").hide("fast");$("#qitarenyuanDiv").show("fast ...