问题 L: 开会--树的最小支配集

本文探讨了一种算法,旨在解决如何在有限的资源下,邀请最少数量的学生参加座谈会,以确保所有学生都能受到震慑。通过构建无向图并使用深度优先搜索(DFS)策略,算法能够高效地确定最佳邀请方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题 L: 开会

时间限制: 1 Sec  内存限制: 128 MB
提交: 111  解决: 20
[提交] [状态] [讨论版] [命题人:admin]

题目描述

开会,是对所有人时间的浪费,是对集体的谋杀。
山区学校的一些学生之间的关系似乎好得有点过头,以至于传出了一些(在风纪委员们看来)不好的绯闻。具体地,有n个学生,n-1条绯闻,每条绯闻的主角都是俩学生。记者们的恶趣味保证任意两个学生,可以通过若干条绯闻直接或间接地联系在一起。
于是学校打算邀请一些学生参加座谈会。
校长相信,假如邀请了某位学生x来开会,那么就能够震慑到x本人,以及和x在同一条绯闻里的学生们。
矿泉水是宝贵的,校长想知道最少需要请多少人来开会,才有可能震慑到所有同学。

 

输入

第一行是 n 表示学生数。 
之后n-1行,每行俩整数x,y,表示学生x和y之间有绯闻。( x≠y,但不一定x<y )

输出

一行,一个整数表示最少要邀请多少人。 

样例输入

5
1 3
5 2
4 3
3 5

样例输出

2

提示

可以选择邀请学生2&3,或者是邀请学生3&5 

对于前10%的数据,n<=15
对于前30%的数据,n<=2000
对于接下来30%的数据,n<=10^5,且有俩学生需要通过n-1条绯闻才能扯上关系。
对于前100%的数据,n<=10^5,1<=x,y<=n

 

居然是板子题,嗯,板子还是很好理解的,可惜当时不知道

 

无向图,两倍的边,所以边开两倍

 

一遍dfs,

求出某个点的父亲,并且将dfs的顺序放入栈中(需要反序)

那么依次弹出栈中点

如果他没被覆盖(震慑),那么标记他父亲(这个就是被拉去开会的那个),这样覆盖(震慑)掉他,他父亲,他父亲的父亲

栈空即结束

 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 1e5+7;
struct Edge{
    int to,next;
}E[maxn<<1];//边
int Fa[maxn],head[maxn],st[maxn],now,cnt,n;//Fa-father,head-链式前向星,st-栈,now-dfs序,cnt-链式前向星边数,n-树节点数
bool vis[maxn],Set[maxn];//vis是-是否震慑某人,Set是-某人去开会
int ans;//答案
void dfs(int x,int dad){
    Fa[x] = dad;
    st[now++] = x;//入栈
    for(int i=head[x];~i;i = E[i].next){
        int v = E[i].to;
        if(v == dad)continue;
        dfs(v,x);
    }
}
void add(int u,int v){
    E[cnt] = {v,head[u]};
    head[u] = cnt++;
    E[cnt] = {u,head[v]};
    head[v] = cnt++;
}
void init(){
    memset(head,-1,sizeof(head));
    memset(Fa,0,sizeof(Fa));
    memset(st,0,sizeof(st));
}
int main(){
    init();
    scanf("%d",&n);
    for(int i=0;i<n-1;i++){
        int x,y;
        scanf("%d%d",&x,&y);
        add(x,y);
    }
    dfs(1,0);
    while(now){//栈不空
        int top = st[--now];//取栈顶(这里理解为倒序遍历数组也行)
        if(!vis[top]){
            if(!Set[Fa[top]]){//选其父亲去开会
                Set[Fa[top]] = 1;
                ans ++;
            }
            vis[top] = 1;//它
            vis[Fa[top]] = 1;//它父亲
            vis[Fa[Fa[top]]] = 1;//它爷爷
        }
    }
    printf("%d\n",ans);
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值