POJ1463 Strategic game (最小点覆盖 or 树dp)

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

给你一棵树形图,问最少多少个点覆盖所有的边。

可以用树形dp做,任选一点,自底向上回溯更新。

dp[i][0] 表示不选i点 覆盖子树所有边的最少点个数,那选i点的话,那么i的邻接节点都是必选的,所以dp[i][0] += dp[i.son][1]

dp[i][1] 表示选i点 覆盖子树所有边的最少点个数,那么i的邻接点可选可不选(而不是一定不选,看注释样例就知道了),所以dp[i][0] += min(dp[i.son][1], dp[i.son][0])

 1 //dp
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <ctime>
10 #include <list>
11 #include <set>
12 #include <map>
13 using namespace std;
14 typedef long long LL;
15 typedef pair <int, int> P;
16 const int N = 1505;
17 vector <int> G[N];
18 int dp[N][2];
19
20 void dfs(int u, int p) {
21     dp[u][0] = 0, dp[u][1] = 1;
22     for(int i = 0; i < G[u].size(); ++i) {
23         int v = G[u][i];
24         if(v == p)
25             continue;
26         dfs(v, u);
27         dp[u][0] += dp[v][1];
28         dp[u][1] += min(dp[v][0], dp[v][1]);
29     }
30 }
31
32 int main()
33 {
34     int n;
35     while(~scanf("%d", &n)) {
36         int u, num, v;
37         for(int i = 1; i <= n; ++i) {
38             scanf("%d:(%d)", &u, &num);
39             while(num--) {
40                 scanf("%d", &v);
41                 G[u].push_back(v);
42                 G[v].push_back(u);
43             }
44         }
45         dfs(0, -1);
46         printf("%d\n", min(dp[0][0], dp[0][1]));
47         for(int i = 0; i < n; ++i)
48             G[i].clear();
49     }
50     return 0;
51 }
52 /*
53 13
54 0:(3) 1 2 3
55 1:(0)
56 2:(2) 4 5
57 3:(2) 6 7
58 4:(0)
59 5:(0)
60 6:(2) 8 9
61 7:(3) 10 11 12
62 8:(0)
63 9:(0)
64 10:(0)
65 11:(0)
66 12:(0)
67 */

边完全覆盖,也就是最小点覆盖所有边。

二分图中最大匹配=最小点覆盖

 1 //dp
 2 #include <algorithm>
 3 #include <iostream>
 4 #include <cstdlib>
 5 #include <cstring>
 6 #include <cstdio>
 7 #include <vector>
 8 #include <cmath>
 9 #include <ctime>
10 #include <list>
11 #include <set>
12 #include <map>
13 using namespace std;
14 typedef long long LL;
15 typedef pair <int, int> P;
16 const int N = 1505;
17 vector <int> G[N];
18 int dp[N][2];
19
20 void dfs(int u, int p) {
21     dp[u][0] = 0, dp[u][1] = 1;
22     for(int i = 0; i < G[u].size(); ++i) {
23         int v = G[u][i];
24         if(v == p)
25             continue;
26         dfs(v, u);
27         dp[u][0] += dp[v][1];
28         dp[u][1] += min(dp[v][0], dp[v][1]);
29     }
30 }
31
32 int main()
33 {
34     int n;
35     while(~scanf("%d", &n)) {
36         int u, num, v;
37         for(int i = 1; i <= n; ++i) {
38             scanf("%d:(%d)", &u, &num);
39             while(num--) {
40                 scanf("%d", &v);
41                 G[u].push_back(v);
42                 G[v].push_back(u);
43             }
44         }
45         dfs(0, -1);
46         printf("%d\n", min(dp[0][0], dp[0][1]));
47         for(int i = 0; i < n; ++i)
48             G[i].clear();
49     }
50     return 0;
51 }
52 /*
53 13
54 0:(3) 1 2 3
55 1:(0)
56 2:(2) 4 5
57 3:(2) 6 7
58 4:(0)
59 5:(0)
60 6:(2) 8 9
61 7:(3) 10 11 12
62 8:(0)
63 9:(0)
64 10:(0)
65 11:(0)
66 12:(0)
67 */

时间: 2024-10-09 14:59:42

POJ1463 Strategic game (最小点覆盖 or 树dp)的相关文章

POJ 1463 Strategic game 最小点覆盖集(树形dp)

点击打开链接 Strategic game Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 6105   Accepted: 2808 Description Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast enough and then he is v

HDU 1054 Strategic Game 最小点覆盖

 最小点覆盖概念:选取最小的点数覆盖二分图中的所有边. 最小点覆盖 = 最大匹配数. 证明:首先假设我们求的最大匹配数为m,那么最小点覆盖必然 >= m,因为仅仅是这m条边就至少需要m个点.然后假如我们已经求得最小覆盖点集,那么在点集中每个点必然有着这样的性质,在于它相连的边里面,一定有一条边的端点不在最小点集中,因为如果连一条这样的边都没有,那这个点完全没有在最小点集的必要,我们任意选取这样的一条边,一定可以形成一个匹配,匹配数与最小点集中的点的个数相等,但现在这仅仅是一个匹配,他必然小于最大

poj1463 Strategic game 树的最小点覆盖

http://poj.org/problem?id=1463 Strategic game Time Limit: 2000MS   Memory Limit: 10000K Total Submissions: 6413   Accepted: 2973 Description Bob enjoys playing computer games, especially strategic games, but sometimes he cannot find the solution fast

树的最小支配集,最小点覆盖,最大独立集两种算法

1.基本概念 对图G=<V,E>, 最小支配集:从V中取尽量少的点组成一个集合,使得V中剩余的点都与取出来的点有边相连 最小点覆盖:从V中取尽量少的点组成一个集合,使得E中所有边都与取出来的点相连 最大独立集:从V中取尽量多的点组成一个集合,使得这些点之间没有边相连 2.贪心法求树的最小支配集,最小点覆盖,最大独立集模板 基本算法: 以最小支配集为例,首先选择一点为根,按照深度优先遍历得到遍历序列,按照所得序列的反向序列的顺序进行贪心,对于一个既不属于支配集也不与支配集中的点相连的点来说,如果

luogu P2700 逐个击破 树dp

传送门 好题啊 给定边权树 求隔离所有指定点的最小花费 考虑树dp的话 自然想到 f[x]表示子树内处理完从根节点出发没有敌人的最小花费 g[x]表示子树内处理完从根节点出发仍有敌人的最小花费 这个时候仍然合法() 又显然根节点是否有敌人是有影响的 所以分类讨论 首先子树没有敌人不用考虑 I. 根节点有敌人的话 f[x]就是inf g[x]直接取f[v]和g[v]+cst[i]最小值 表示是否切x->v这条边 II. 如果根节点没有 那么g[x]维护的就是选择一个花费最小的儿子切 而这样的花费就

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

最小支配集: 从V中选取尽量少的点组成一个集合,让V中剩余的点都与取出来的点有边相连. (点) 最小点覆盖: 从V中选取尽量少的点组成一个集合V1,让所有边(u,v)中要么u属于V1,要么v属于V1 (边) 最大独立集: 从V中选取尽量多的点组成一个集合,让这些点中间没有边项链,也就是说对于任何一条边,u,v不能同时属于集合V1. 1.贪心算法 首先选取一个点为根节点,求出所有节点对应的DFS序列,按照所得序列反向进行贪心,这样保证对于每个点来说,当子树都被处理过之后才会处理该节点 int p[

树的最小支配集 最小点覆盖 与 最大独立集 (图论)

做 战略游戏 这道题的时候看到了这个东西,于是就来这里写了一下. 首先看一下三者的定义: 定义1 对于图G=(V,E)来说,最小支配集指的是从V中取尽量少的点组成一个集合,使得对于V中剩余的点都与取出来的点有边相连.也就是说,设V‘是图G的一个支配集,则对于图中的任意一个顶点u,要么属于集合V’,要么与V‘中的顶点相邻.在V’中出去任何元素后V‘不再是支配集,则支配集是极小支配集.称G的所有支配集中顶点个数最少的支配集为最小支配集,最小支配集中顶点的个数称为支配数. 定义2 对于图G=(V,E)

树的问题小结(最小生成树、次小生成树、最小树形图、LCA、最小支配集、最小点覆盖、最大独立集)

树的定义:连通无回路的无向图是一棵树. 有关树的问题: 1.最小生成树. 2.次小生成树. 3.有向图的最小树形图. 4.LCA(树上两点的最近公共祖先). 5.树的最小支配集.最小点覆盖.最大独立集. 一.最小生成树 解决的问题是:求无向图中边权值之和最小的生成树. 算法有Kruskal和Prim. Kruskal使用前向星和并查集实现,可以存储重边(平行边),时间复杂度是O(m log m  +  m),m是边的数量. Prim使用邻接矩阵建图,不可以存储重边(平行边),如果出现重边,存储的

树的最小支配集、最小点覆盖、最大独立集【模板】

最小支配集:指从所有顶点中取尽量少的点组成一个集合,使得剩下的所有点都与取出来的点有边相连.顶点个数最小的支配集被称为最小支配集.这里用贪心法来求. 1.以1号点深度优先搜索整棵树,求出每个点在DFS中的编号和每个点的父亲节点编号. 2.按DFS的反向序列检查,如果当前点既不属于支配集也不与支配集中的点相连,且它的父亲也不属于支配集,将其父亲点加入支配集,支配集个数加1. 3.标记当前结点.当前结点的父节点(属于支配集).当前结点的父节点的父节点(与支配集中的点相连). #include<ios