中二羊:关键人物

该文章讨论了一种图论问题,涉及现代社会中的人际关系网络。通过给定的无向图表示朋友关系,目标是找出那些如果生病(从网络中移除)会导致其他人无法互相联系的关键人物。文章提到了使用Tarjan算法来解决这个问题,识别出图中的割点,这些割点即为关键人物。
摘要由CSDN通过智能技术生成

关键人物

翻了一下之前(指初二)打算做的难题,但是一直没时间做,几年后翻出来打算水一下。

题目

题目背景

现代社会人们的通信非常方便,社交圈也迅速扩大,可能你不认识某个人,但是通过你的朋友,朋友的朋友……,也能和这个人联系起来。

题目描述

ZEY 在研究人际关系,在这个人际关系中,有 n n n 个人,用 1 1 1 n n n 的编号来表示每一个人,有一些人两两之间是朋友关系,朋友之间可以传递信息,如果 A 和 B 是朋友,B 和 C 是朋友,那么 A 和 C 也能传递信息。但是如果 B 生病了,那么 A 和 C 就联系不上了。那么 B 被称为关键人物。
ZEY 已经知道,在这个人际关系中,每个人都有办法联系到其他的任何一个人,现在他想知道这个人际关系中,哪些人生病会出现有两个人联系不上的情况,即关键人物有哪些。

输入格式

输入分 m + 1 m+1 m+1
第一行输入两个整数 n n n m m m n n n 表示人际关系中的人数,m表示朋友关系的数量
接下来m行,每一行两个整数 x x x , y y y ,表示 x x x y y y 之间是朋友关系

输出格式

输出1行,将所有关键人物按编号从小到大输出,并用空格隔开

样例 #1

样例输入 #1
3 2
1 2
2 3
样例输出 #1
2

样例 #2

样例输入 #2
5 6
1 2
1 3
3 2
3 4
3 5
5 4
样例输出 #2
3

提示

对于100%的数据, 1 < n ≤ 5 × 1 0 4 1<n≤5×10^4 1<n5×104, 1 < m ≤ 1.5 × 1 0 5 1<m≤1.5×10^5 1<m1.5×105

解法

通过分析题意可得,这就是求无向图的割点。
删了这割点后整个图就不会连通。
然后我们就可以用 Tarjan 水过去了。
如果还是理解不了见 OI-Wiki

代码

#include<cstdlib>
#include<cstring>
#include<cstdio>
#include<cctype>
#include<algorithm>
using std::min;
typedef long long LL;
typedef unsigned long long ULL;
namespace FastIo{
    typedef __uint128_t ULLL;
    static char buf[100000],*p1=buf,*p2=buf,fw[100000],*pw=fw;
    #define gc p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++
    inline void pc(const char &ch){
    	if(pw-fw==100000)fwrite(fw,1,100000,stdout),pw=fw;
    	*pw++=ch;
	}
    #define fsh fwrite(fw,1,pw-fw,stdout),pw=fw
	struct FastMod{
        FastMod(ULL b):b(b),m(ULL((ULLL(1)<<64)/b)){}
        ULL reduce(ULL a){
            ULL q=(ULL)((ULLL(m)*a)>>64);
            ULL r=a-q*b;
            return r>=b?r-b:r;
        }
        ULL b,m;
    }HPOP(10);
    struct QIO{
    	char ch;
    	int st[40];
    	template<class T>inline void read(T &x){
    		x=0,ch=gc;
    		while(!isdigit(ch))ch=gc;
    		while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=gc;}
		}
		template<class T>inline void write(T a){
			do{st[++st[0]]=HPOP.reduce(a);a/=10;}while(a);
			while(st[0])pc(st[st[0]--]^48);
		}
	}qrw;
}
using namespace FastIo;
#define NUMBER1 50000
#define NUMBER2 150000
#define P(A) A=-~A
#define fione_i(begin,end) for(register int i=begin;i<=end;P(i))
#define tt_i(u) for(register int i=head[u];i;i=e[i].next)
struct EDGE{int next,to;}e[(NUMBER2<<1)+5];
int head[NUMBER1+5],tot(0),cnt(0),n,m,id[NUMBER1+5],low[NUMBER1+5];
bool cut[NUMBER2+5];
inline void add(const int &u,const int &v){e[++tot].next=head[u];e[tot].to=v,head[u]=tot;}
void Tarjan(int u,int fa){
	int kid(0);
	id[u]=low[u]=++cnt;
	tt_i(u){
		if(!id[e[i].to]){
			Tarjan(e[i].to,fa);
			low[u]=min(low[u],low[e[i].to]);
			if(low[e[i].to]>=id[u]&&u!=fa)cut[u]=true;
			if(u==fa)P(kid);
		}
		low[u]=min(low[u],id[e[i].to]);
	}
	if(u==fa&&kid>=2)cut[u]=true;
}
signed main(){
	qrw.read(n);
	qrw.read(m);
	int x,y,ans(0);
	fione_i(1,m){
		qrw.read(x);
		qrw.read(y);
		add(x,y);add(y,x);
	}
	fione_i(1,n)if(!id[i])Tarjan(i,i);
	fione_i(1,n)
		if(cut[i]){
			qrw.write(i);
			pc(' ');
		}
	fsh;
    exit(0);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值