正题
题目链接:https://www.luogu.com.cn/problem/AT4518
题目大意
给出nnn个点mmm条边的一张简单无向联通图,求能否把它分成三个可重复点的环。
1≤n,m≤1051\leq n,m\leq 10^51≤n,m≤105
解题思路
相当于你要去掉图上的两个环后依旧有欧拉回路
首先原本肯定得有欧拉回路,考虑怎么去掉这两个环。
如果图上有一个度数不小于666的点,那么这个点就可以直接拉出三个环。
度数为222的点只能经过一遍,显然不能分环。
那就只剩下度数为444的点了,只有一个显然不行,如果有三个或以上的度数为444的点,那么直接拉出它们之间的路径就有三个环了
有两个的情况比较特殊,其实是一定可以多拉出两个环的,但是如果从某个度数为444的点出发的所有路径都必须经过另一个点,那么拉出的这两个环会把图变得不连通,所以需要特判一下这种情况。
时间复杂度O(n+m)O(n+m)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;
}