我是靠谱客的博主 迷你外套,这篇文章主要介绍树的最小支配集、最小点覆盖、最大独立集 (贪心orDP),现在分享给大家,希望可以做个参考。

树的最小支配集:点集中取出尽量少的点,使剩下的点与取出来的点都有边相连。
树的最小点覆盖:点集中取出尽量少的点,使得所有边都与选出的点相连。
树的最大独立集:点集中取出尽量多的点,使得这些点两两之间没有边相连。

贪心模板:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
#include<bits/stdc++.h> #define ll long long #define sl(x) scanf("%lld",&x) using namespace std; const int N = 1e6+5; struct node{ int next,v; }p[N]; int head[N],cnt,vis[N],now = 0; ll fa[N],deep[N],n; void init() { for(int i = 0;i < n+1;i++) head[i] = -1; cnt = 0; } void dfs(int u,int f) { fa[u] = f; deep[now++] = u; for(int i = head[u];~i;i = p[i].next) { if(p[i].v == f) continue; dfs(p[i].v,u); } } ll s[N]; void add(int u,int v) { p[cnt].v = v; p[cnt].next = head[u]; head[u] = cnt++; } int main() { ll i,j,k,x,y; sl(n); init(); for(i = 0;i < n-1;i++) { sl(x);sl(y); add(x,y); add(y,x); } dfs(1,0); //求解 }

最小支配集:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
ll ans = 0; for(i = now-1;i >= 0;i--) { ll u = deep[i]; if(!vis[u]) { if(!s[fa[u]]) { s[fa[u]] = 1; ans++; } vis[u] = 1; vis[fa[u]] = 1; vis[fa[fa[u]]] = 1; } }

最小点覆盖:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
ll ans = 0; for(i = now-1;i >= 0;i--) { ll u = deep[i]; if(!vis[u] && ! vis[fa[u]]) { s[fa[u]] = 1; ans++; vis[u] = 1; vis[fa[u]] = 1; } } printf("%lldn",ans);

最大独立集:

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
ll ans = 0; for(i = now-1;i >= 0;i--) { ll u = deep[i]; if(!vis[u]) { s[u] = 1; ans++; vis[u] = 1; vis[fa[u]] = 1; } } printf("%lldn",ans);

DP:

最小支配集:
dp[i][0]: i属于支配集,并且以点i为根的子树都被覆盖了的情况下的最少点数
dp[i][1]: i不属于支配集,并且以i为根的子树都被覆盖,并且i被其中不少于1个子节点覆盖的情况下的最少点数
dp[i][2]: i不属于支配集,并且以i为根的子树都被覆盖,并且i没被子节点覆盖的情况下的最少点数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
void solve(int u,int fa) { dp[u][2] = 0; dp[u][0] = 1; int s = 0,sum = 0,inc = mod; for(int i = head[u];~i;i = p[i].next) { int v = p[i].v; if(v == fa) continue; solve(v,u); dp[u][0] += min(dp[v][0],min(dp[v][1],dp[v][2])); if(dp[v][0] <= dp[v][1]) { sum += dp[v][0]; s = 1; } else { sum += dp[v][1]; inc = min(inc,dp[v][0]-dp[v][1]); } if(dp[v][1] != Mod && dp[u][2] != mod) dp[u][2] += dp[v][1]; else dp[u][2] = Mod; if(inc == mod && !s) dp[u][1] = Mod; else { dp[u][1] = sum; if(!s) dp[u][1] += inc; } } }

最小点覆盖:
dp[i][0]: i属于点集合,并且以点i为根的自述中所连接的边都被覆盖的情况下点覆盖集所包含的最少点数
dp[i][1]: i不属于点集合,并且以点i为根的自述中所连接的边都被覆盖的情况下点覆盖集所包含的最少点数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
void solve(int u,int fa) { dp[u][0] = 1; dp[u][1] = 0; for(int i = head[u];~i;i = p[i].next) { int v = p[i].next; if(v = fa) continue; solve(v,u); dp[u][0] += min(dp[v][0],dp[v][1]); dp[u][1] += dp[v][0]; } }

最大独立集:
dp[i][0]: 点i属于独立集的情况下,最大独立集中点的个数
dp[i][1]: 点i属于独立集的情况下,最大独立集中点的个数

复制代码
1
2
3
4
5
6
7
8
9
10
11
12
13
void solve(int u,int fa) { dp[u][0] = 1; dp[u][1] = 0; for(int i = head[u];~i;i = p[i].next) { int v = p[i].v; if(v == fa) continue; solve(v,u); dp[u][0] += dp[v][1]; dp[u][1] += max(dp[v][0],dp[v][1]); } }

 

最后

以上就是迷你外套最近收集整理的关于树的最小支配集、最小点覆盖、最大独立集 (贪心orDP)的全部内容,更多相关树的最小支配集、最小点覆盖、最大独立集内容请搜索靠谱客的其他文章。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(82)

评论列表共有 0 条评论

立即
投稿
返回
顶部