树形DP 树的最小支配集,最小点覆盖与最大独立集
Posted joeylee97
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形DP 树的最小支配集,最小点覆盖与最大独立集相关的知识,希望对你有一定的参考价值。
最小支配集:
从V中选取尽量少的点组成一个集合,让V中剩余的点都与取出来的点有边相连。
(点)
最小点覆盖:
从V中选取尽量少的点组成一个集合V1,让所有边(u,v)中要么u属于V1,要么v属于V1
(边)
最大独立集:
从V中选取尽量多的点组成一个集合,让这些点中间没有边项链,也就是说对于任何一条边,u,v不能同时属于集合V1.
1.贪心算法
首先选取一个点为根节点,求出所有节点对应的DFS序列,按照所得序列反向进行贪心,这样保证对于每个点来说,当子树都被处理过之后才会处理该节点
int p[MAXN]; bool select[MAXN]; int newpos[MAXN]; int now, n, m; //最小支配集 int greedy1() { bool s[MAXN] = { 0 }; bool set[MAXN] = { 0 }; int ans = 0; int i; for (i = n - 1; i >= 0; i--) { int t = newpos[p[t]]; if (!s[t]) { if (!set[p[t]]) { set[p[t]] = true; ans++; } s[t] = s[p[t]] = s[p[p[t]]] = true; } } return ans; } //最小点覆盖 int greedy2() { bool s[MAXN] = { 0 }; bool set[MAXN] = { 0 }; int ans = 0; for (int i = n - 1; i >= 1; i--)//不可以检查根节点,p[root] = root { int t = newpos[i]; if (!s[t] && !s[p[t]]) { set[p[t]] = true; ans++; s[t] = s[p[t]] = true; } } } //最大独立集 int greedy3() { int ans = 0; bool s[MAXN] = { 0 }; bool set[MAXN] = { 0 }; for (int i = 1; i >= 0; i--) { int t = newpos[i]; if (!s[t]) { set[t] = true; ans++; s[t] = s[p[t]] = true; } } return ans; }
2.树形DP
1.dp[i][0]: 表示点i属于支配集,并且以点i为根的子树都被覆盖了的情况下支配集中包含点最少的个数
2.dp[i][1] i不属于支配集,而且以i为根的子树都被覆盖而且i被其中不少于一个子节点覆盖情况下支配集所包含最少点的个数
3.dp[i][2] i不属于支配集,而且i为根的子树都被覆盖而且I没有被子节点覆盖的情况下支配集报验最少点的个数
对于第一情况,对子节点无限制
dp[i][0] = 1 + 西格玛min(dp[u][0],dp[u][1],dp[u][2]) p[u] = t
对于第二红情况, 如果i没有子节点那么dp[i][1] = INF,子节点必须被覆盖,所以和状态dp[i][2]无关的!
dp[i][1] = 西格玛min(dp[u][0],dp[u][1]) + inc
如果选取了某一个dp[u][0] inc = 0;
else inc = min(dp[u][0] - dp[u][1])
选取的时候注意如果全部选的都是dp[u][1]那父节点没办法被覆盖啦!所以判断一下
对于第三种情况,i不属于支配集,i的子树都被覆盖,说明i和i的儿子都不是支配集的!
dp[i][2] = 西格玛dp[u][1]
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<sstream> #include<algorithm> #include<queue> #include<deque> #include<iomanip> #include<vector> #include<cmath> #include<map> #include<stack> #include<set> #include<functional> #include<fstream> #include<memory> #include<list> #include<string> using namespace std; typedef long long LL; typedef unsigned long long ULL; #define N 31 #define INF 1000000009 #define eps 0.00000001 #define sf(a) scanf("%d",&a) const int MAXN = 1e5 + 3; int dp[MAXN][3]; int head[MAXN]; void DP(int u, int p) { dp[u][2] = 0; dp[u][0] = 1; bool s = false; int sum = 0, inc = INF; int k; for (k = head[u]; k != -1; k = E[k].next) { int to = E[k].to; if (to == p) continue; DP(to, u); dp[u][0] += min(dp[to][0], dp[to][1], dp[to][2]); if (dp[to][0] < dp[to][1]) { s = true; sum += dp[to][0]; } else { sum += dp[to][1]; inc = min(inc, dp[to][0] - dp[to][1]); } if (dp[to][1] != INF&&dp[u][2] != INF) dp[u][2] += dp[to][1]; else dp[u][2] = INF; } if (inc == INF && !s) dp[u][1] = INF; else { dp[u][1] = sum; if (!s) dp[u][1] += inc; } }
对于最小点覆盖
dp[u][0] u点被覆盖
dp[u][1] u点没被覆盖
int dp[MAXN][3]; int head[MAXN]; void DP(int u, int p) { dp[u][0] = 1; dp[u][1] = 0; int k, to; for (k = head[u]; k != -1; k = E[k].next) { to = E[k].to; if (to == p) continue; DP(to, u); dp[u][0] += min(dp[to][0], dp[to][1]); dp[u][1] += dp[to][0]; } }
以上是关于树形DP 树的最小支配集,最小点覆盖与最大独立集的主要内容,如果未能解决你的问题,请参考以下文章