树的最小支配集poj3659、最小点覆盖、最大独立集

推荐讲解 点击打开链接

对于树图,贪心法求最小支配集、最小点覆盖、最大独立集。

最小支配集:选取尽量少的点组成一个集合,对图中任意一点u,在集合中一定存在于u相邻的点。


最小点覆盖:选取尽量少的点组成一个集合,对图中任意条边<u,v>,u,v至少有一点在集合中。


最大独立集:选取尽量多的点组成一个集合,集合中任意两点没有边。


三种题目的求法:

int pos[10101];//深搜顺序
int fa[10101];//父节点
int select[10101];//标记点是否选中支配集

都需要dfs预处理pos[]和fa[]数组(链式前向星)

void dfs(int s,int &k)
{
    pos[k++]=s;
    vis[s]=1;
    for(int i=head[s];~i;i=e[i].next)
    {
        int t=e[i].t;
        if(!vis[t])
        {
            fa[t]=s;
            dfs(t,k);
        }
    }
}
【最小支配集】:
int greedy(int root)
{
    memset(vis,0,sizeof (vis));
    int k=0;
    fa[root]=root;//根节点的祖先视为自己!
    dfs(root,k);//预处理
    //if(k<n)return -1; //原图没有构成树
    memset(vis,0,sizeof (vis));
    memset(select,0,sizeof (select));
    int ans=0;
    for(int i=k-1;i>=0;i--)
    {
        int t=pos[i];
        if(!vis[t])
        {
            if(!select[fa[t]])
            {
                select[fa[t]]=1;
                ans++;
            }
            vis[t]=vis[fa[t]]=vis[fa[fa[t]]]=1;
        }
    }
    return ans;
}
【最小点覆盖】:
int greedy(int root)
{
    memset(vis,0,sizeof (vis));
    int k=0;
    fa[root]=root;//根节点的祖先视为自己!
    dfs(root,k);//预处理
    //if(k<n)return -1; //原图没有构成树
    memset(vis,0,sizeof (vis));
    memset(select,0,sizeof (select));
    int ans=0;
    for(int i=k-1;i>=0;i--)
    {
        int t=pos[i];
        if(!vis[t]&&!vis[fa[t]])
        {
            select[fa[t]]=1;
            ans++;
            vis[t]=vis[fa[t]]=1;
        }
    }
    return ans;
}
【最大独立集】:
int greedy(int root)
{
    memset(vis,0,sizeof (vis));
    int k=0;
    fa[root]=root;//根节点的祖先视为自己!
    dfs(root,k);//预处理
    //if(k<n)return -1; //原图没有构成树
    memset(vis,0,sizeof (vis));
    memset(select,0,sizeof (select));
    int ans=0;
    for(int i=k-1;i>=0;i--)
    {
        int t=pos[i];
        if(!vis[t])
        {
            select[t]=1;
            ans++;
            vis[t]=vis[fa[t]]=1;
        }
    }
    return ans;
}


例题:

【poj3659 最小支配集】:

分析:john要在n个点中选一些点建信号塔,已知每个点可以收到自己点和相邻点的信号塔信号。

问最少要建几个塔。

【代码】:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<iostream>
using namespace std;
struct node{
    int s,t,next;
}e[20101];
int head[10101],cnt;
void add(int u,int v)
{
    e[cnt]=node{u,v,head[u]};
    head[u]=cnt++;
}
int pos[10101];//深搜顺序
int fa[10101];//父节点
bool vis[10101];
int select[10101];//标记点是否选中支配集
void dfs(int s,int &k)//预处理pos[]和fa[]
{
    pos[k++]=s;
    vis[s]=1;
    for(int i=head[s];~i;i=e[i].next)
    {
        int t=e[i].t;
        if(!vis[t])
        {
            fa[t]=s;
            dfs(t,k);
        }
    }
}
int greedy(int root)
{
    memset(vis,0,sizeof (vis));
    int k=0;
    fa[root]=root;//根节点的祖先视为自己!
    dfs(root,k);//预处理
    //if(k<n)return -1; //原图没有构成树
    memset(vis,0,sizeof (vis));
    memset(select,0,sizeof (select));
    int ans=0;
    for(int i=k-1;i>=0;i--)
    {
        int t=pos[i];
        if(!vis[t])
        {
            if(!select[fa[t]])
            {
                select[fa[t]]=1;
                ans++;
            }
            vis[t]=vis[fa[t]]=vis[fa[fa[t]]]=1;
        }
    }
    return ans;
}
int main()
{
    int n,u,v;
    cin>>n;
    memset(head,-1,sizeof(head));
    cnt=0;
    for(int i=1;i<n;i++)
    {
        cin>>u>>v;
        add(u,v);
        add(v,u);
    }
    printf("%d\n",greedy(1));
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

雪的期许

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值