正题
题目链接: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]&°[i]==2)last=0,dfs(i);
if(ans)puts("Yes");
else puts("No");
return 0;
}