特殊图判断

K LilaS的特殊图判断 - 第七届校赛正式赛 —— 补题

题目大意:

给定一个无向图,图中有 N N N 个顶点,编号为 1 − N 1-N 1N M M M 条边,编号为 1 − M 1-M 1M 。第 i i i 条边连接顶点 u i u_i ui v i v_i vi 。存在重边和自环。

有没有一种算法能快速判断该无向图中的每个连通部分是否满足:连通部分的顶点和边的数量相同

如果该图中每个连通部分都满足条件,则输出 Yes;否则,输出 No

1 < = N < = 2 ∗ 1 0 5 1<=N<=2*10^5 1<=N<=2105

0 < = M < = 2 ∗ 1 0 5 0<=M<=2*10^5 0<=M<=2105

1 < = u i < = v i < = N 1<=u_i<=v_i<=N 1<=ui<=vi<=N

思路:

考虑并查集,维护祖先节点中 顶点个数 和 边的个数

int fa[N],sz[N],ver[N];

fa[i]=i,sz[i]=1,ver[i]=0;

int u,v;
u=find(u),v=find(v);
如果祖先节点相同,那么点的个数不用增加,考虑给祖先节点多加一条边
    if(u==v){
        ver[u]++;
    }
如果祖先节点不相同,那么将这两个连通块合并,随便找一个节点为祖宗节点即可
    else{
        fa[v]=u;
        sz[u]+=sz[v];
        ver[u]+=ver[v]+1;//这条边
    }

代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
#define fi first
#define se second
#define PII pair<int,int>
#define lowbit(x) x&-x
#define ALL(x) x.begin(),x.end()

const int mod = 1e9 + 7;
const int N = 2e5 + 10;

int fa[N],sz[N],ver[N];
int n,m;
int find(int x){
	if(x==fa[x]) return x;
	return fa[x]=find(fa[x]);
}


void solve() {
	cin>>n>>m;
	for(int i=1;i<=n;i++){
		fa[i]=i;
		sz[i]=1;
		ver[i]=0;
	}
	for(int i=1;i<=m;i++){
		int u,v;cin>>u>>v;
		
		u=find(u),v=find(v);
		if(u==v){
			ver[u]++;
			continue;
		}
		if(u!=v){
			fa[v]=u;
			sz[u]+=sz[v];
			ver[u]+=ver[v]+1;
		}else{
			ver[u]++;
		}
	}
	
//	cout<<'\n';
	for(int i=1;i<=n;i++){
		int u=find(i);
//		cout<<sz[u]<<" "<<ver[u]<<'\n';
		if(sz[u]!=ver[u]){
			cout<<"No\n";
			return ;
		}
	}
	cout<<"Yes\n";
}

signed main() {
	std::ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int T = 1;
//	cin >> T;
	while (T--) {
		solve();
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值