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

概述

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

贪心模板:

#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);
	//求解
}

最小支配集:

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;
	}
}

最小点覆盖:

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);

最大独立集:

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没被子节点覆盖的情况下的最少点数

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为根的自述中所连接的边都被覆盖的情况下点覆盖集所包含的最少点数

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属于独立集的情况下,最大独立集中点的个数

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)的全部内容,希望文章能够帮你解决树的最小支配集、最小点覆盖、最大独立集 (贪心orDP)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

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

评论列表共有 0 条评论

立即
投稿
返回
顶部