AT4518[AGC032C]Three Circuits【欧拉回路】

正题

题目链接:https://www.luogu.com.cn/problem/AT4518


题目大意

给出\(n\)个点\(m\)条边的一张简单无向联通图,求能否把它分成三个可重复点的环。
\(1\leq n,m\leq 10^5\)


解题思路

相当于你要去掉图上的两个环后依旧有欧拉回路

首先原本肯定得有欧拉回路,考虑怎么去掉这两个环。

如果图上有一个度数不小于\(6\)的点,那么这个点就可以直接拉出三个环。

度数为\(2\)的点只能经过一遍,显然不能分环。

那就只剩下度数为\(4\)的点了,只有一个显然不行,如果有三个或以上的度数为\(4\)的点,那么直接拉出它们之间的路径就有三个环了

有两个的情况比较特殊,其实是一定可以多拉出两个环的,但是如果从某个度数为\(4\)的点出发的所有路径都必须经过另一个点,那么拉出的这两个环会把图变得不连通,所以需要特判一下这种情况。

时间复杂度\(O(n+m)\)


code

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int N=1e5+10;
struct node{
	int to,next;
}a[N<<1];
int n,m,tot,ans,last,deg[N],ls[N];
bool v[N];
void addl(int x,int y){
	a[++tot].to=y;
	a[tot].next=ls[x];
	ls[x]=tot;return;
}
void dfs(int x){
	if(v[x])return;v[x]=1;
	for(int i=ls[x];i;i=a[i].next){
		int y=a[i].to;
		if(deg[y]==4){
			ans+=(y==last);
			last=y;
		}
		else dfs(y);
	}
	return;
}
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=m;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		addl(x,y);addl(y,x);
		deg[x]++;deg[y]++;
	}
	int cnt=0,flag=0;
	for(int i=1;i<=n;i++)
		if(deg[i]&1)return puts("No")&0;
		else if(deg[i]>=6)flag=1;
		else cnt+=(deg[i]==4);
	if(flag||cnt>2)return puts("Yes")&0;
	if(cnt<=1)return puts("No")&0;
	for(int i=1;i<=n;i++)
		if(!v[i]&&deg[i]==2)last=0,dfs(i);
	if(ans)puts("Yes");
	else puts("No");
	return 0;
}
原文地址:https://www.cnblogs.com/QuantAsk/p/14442390.html