题意:有N个点,N-1条边,任意两点可达,由此形成了一棵树。选取一个点a,它可覆盖自己以及与自己相邻的点,选取尽量少的点a,使得树中所有点都被覆盖,即求树的最小点支配集。

分析:

1、对于每一个点cur,要想使其被覆盖,有三种情况:

dp[cur][0]---在该点建立塔

dp[cur][1]---在该点的子结点建立塔

dp[cur][2]---在该点的父结点建立塔

2、对于点cur的子结点x,要使其被覆盖:

(1)dp[cur][0] += Min(Min(dp[x][0], dp[x][1]), dp[x][2]);

在cur处建塔的情况下,x可建塔,x的子节点可建塔,x的父结点即cur建塔,三者取最小值,并累加。

(2)dp[cur][2] += Min(dp[x][0], dp[x][1]);

在cur的父结点建塔的情况下,x可建塔,x的子结点可建塔,两者取最小值,并累加。

(3)dp[cur][1] += Min(dp[x][0], dp[x][1]);

在cur的子结点建塔的情况下,至少需要cur的一个子结点建塔cur才能被覆盖,所以对于每一个子结点x,x可建塔,x的子结点可建塔,两者取最小值

与此同时,记录在取最小值的情况下,cur是否有能建塔的子结点,若没有,需要将cur的一个子结点变成可建塔,选取abs(dp[x][1] - dp[x][0])最小的子结点x改变即可。

3、dp[cur][0]最后要加1,因为在cur点要建塔。

#pragma comment(linker, "/STACK:102400000, 102400000")
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cctype>
#include<cmath>
#include<iostream>
#include<sstream>
#include<iterator>
#include<algorithm>
#include<string>
#include<vector>
#include<set>
#include<map>
#include<stack>
#include<deque>
#include<queue>
#include<list>
#define Min(a, b) ((a < b) ? a : b)
#define Max(a, b) ((a < b) ? b : a)
const double eps = 1e-8;
inline int dcmp(double a, double b){
if(fabs(a - b) < eps) return 0;
return a > b ? 1 : -1;
}
typedef long long LL;
typedef unsigned long long ULL;
const int INT_INF = 0x3f3f3f3f;
const int INT_M_INF = 0x7f7f7f7f;
const LL LL_INF = 0x3f3f3f3f3f3f3f3f;
const LL LL_M_INF = 0x7f7f7f7f7f7f7f7f;
const int dr[] = {0, 0, -1, 1, -1, -1, 1, 1};
const int dc[] = {-1, 1, 0, 0, -1, 1, -1, 1};
const int MOD = 1e9 + 7;
const double pi = acos(-1.0);
const int MAXN = 10000 + 10;
const int MAXT = 10000 + 10;
using namespace std;
int N;
vector<int> v[MAXN];
int dp[MAXN][5];
void dfs(int cur, int father){
memset(dp[cur], 0, sizeof dp[cur]);
int len = v[cur].size();
int dif = INT_INF;
bool ok = false;
for(int i = 0; i < len; ++i){
int x = v[cur][i];
if(x == father) continue;
if(dp[x][0] == INT_INF) dfs(x, cur);
dp[cur][0] += Min(Min(dp[x][0], dp[x][1]), dp[x][2]);
dp[cur][2] += Min(dp[x][0], dp[x][1]);
dif = Min(dif, abs(dp[x][1] - dp[x][0]));
if(dp[x][0] < dp[x][1]){
ok = true;
dp[cur][1] += dp[x][0];
}
else{
dp[cur][1] += dp[x][1];
}
}
++dp[cur][0];
if(!ok) dp[cur][1] += dif;
}
int main(){
scanf("%d", &N);
for(int i = 0; i < N - 1; ++i){
int a, b;
scanf("%d%d", &a, &b);
v[a].push_back(b);
v[b].push_back(a);
}
memset(dp, INT_INF, sizeof dp);
dfs(1, -1);
printf("%d\n", Min(dp[1][0], dp[1][1]));
return 0;
}

  

POJ - 3659 Cell Phone Network(树形dp---树的最小点支配集)的更多相关文章

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

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

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

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

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

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

  4. 树形DP 树的最小支配集,最小点覆盖与最大独立集

    最小支配集: 从V中选取尽量少的点组成一个集合,让V中剩余的点都与取出来的点有边相连. (点) 最小点覆盖: 从V中选取尽量少的点组成一个集合V1,让所有边(u,v)中要么u属于V1,要么v属于V1 ...

  5. POJ 3659 Cell phone Network (树的最小点覆盖, 树形DP)

    题意: 给定一棵树,每个点可以覆盖自己和相邻的点, 求最少要多少个点覆盖图 #include <cstdio> #include <cstring> #include < ...

  6. POJ 3659 Cell Phone Network (树dp)

    题目链接:http://poj.org/problem?id=3659 给你一个树形图,一个点可以覆盖他周围连接的点,让你用最少的点覆盖所有的点. dp[i][0]表示用i点来覆盖,dp[i][1]表 ...

  7. POJ 3342 Party at Hali-Bula (树形dp 树的最大独立集 判多解 好题)

    Party at Hali-Bula Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 5660   Accepted: 202 ...

  8. 树形DP+树状数组 HDU 5877 Weak Pair

    //树形DP+树状数组 HDU 5877 Weak Pair // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 // 这道题要离散化 #i ...

  9. [HDU 5293]Tree chain problem(树形dp+树链剖分)

    [HDU 5293]Tree chain problem(树形dp+树链剖分) 题面 在一棵树中,给出若干条链和链的权值,求选取不相交的链使得权值和最大. 分析 考虑树形dp,dp[x]表示以x为子树 ...

随机推荐

  1. 51nod 1099:任务执行顺序 贪心

    1099 任务执行顺序 基准时间限制:1 秒 空间限制:131072 KB 分值: 20 难度:3级算法题  收藏  取消关注 有N个任务需要执行,第i个任务计算时占R[i]个空间,而后会释放一部分, ...

  2. other#nginx配置

    #user nobody; worker_processes ; #error_log logs/error.log; #error_log logs/error.log notice; #error ...

  3. 046、Java中使用if…else判断

    01.代码如下: package TIANPAN; /** * 此处为文档注释 * * @author 田攀 微信382477247 */ public class TestDemo { public ...

  4. 吴裕雄--天生自然java开发常用类库学习笔记:线程常用的操作方法

    class MyThread implements Runnable{ // 实现Runnable接口 public void run(){ // 覆写run()方法 for(int i=0;i< ...

  5. 使用Vue+JFinal框架搭建前后端分离系统

    前后端分离作为Web开发的一种方式,现在应用越来越广泛.前端一般比较流行Vue.js框架,后端框架比较多,网上有很多Vue+SpringMVC前后端分离的demo,但是Vue+JFinal框架貌似没有 ...

  6. 《ES6标准入门》(阮一峰)--4.字符串的扩展

    1.字符的 Unicode 表示法 ES6 加强了对 Unicode 的支持,允许采用\uxxxx形式表示一个字符,其中xxxx表示字符的 Unicode 码点. "\u0061" ...

  7. c++程序—选择结构

    if(判断条件){执行语句} #include<iostream> using namespace std; #include<string> int main() { ; c ...

  8. I0.0 上升边沿 清空 MW10~MW58 联系多个知识点融合

    编写程序 在I1.2 的上升边沿 触发 MW8+1的程序 实现方式1 M1.1 为中间变量 对应的STL语句表 执行结果 OK 已经仿真 . 现在尝试第2种方法 实现方式2: M1.1也是中间变量 S ...

  9. c#实现"扫描检测硬件改动"

    public static class Win32Api { public const int CM_LOCATE_DEVNODE_NORMAL = 0x00000000; public const ...

  10. Dockerfile详解,以及构建自定义镜像

    Dockerfile使用 前面的操作我们一直下载下载官方已经构建好的镜像,直接下载后就可以run,如果我们想要在镜像中添加自己的应用,比如在tomcat中添加自己的app,构建一个自定义的镜像,那么我 ...