【AtCoder Grand Contest 032 C】Three Circuits
构造。
题目大意:
给定一张无向连通图,问能否找到三条回路,使得三条回路的边集的交为空,且边集的并为所有边。
题解:
由于要把原图拆成三条回路,且原图连通,所以原图本身一定能形成回路,故所有顶点的度数必须是偶数。
考虑度数最大的顶点的度数。
若最大为 $2$,则只能是单个环,不存在方案。
若最大超过 $4$,则这个度数最大的点出发,一定能连至少三个环,必定存在方案。
若最大为 $4$,并且这样的点超过 $2$ 个,则一定可以(考虑一个结点所在的两个子回路)。
若最大为 $4$,并且这样的点只有 $1$ 个,则一定不行。
若最大为 $4$,并且这样的点恰好两个,则分两种情况:
- 这两个四度顶点同时在两个不同环上。那么去掉这两个环就没有其他环了,不行。
- 这两个四度顶点在一个环上,且另外各自在另一个环上。那么是可以的。
在判上面这个情况的时候,可以去掉其中一个四度顶点,然后判断剩下的点能否形成环即可。
Code:
#include<cstdio>
#include<algorithm>
const int N=1e5+6;
int n,m,deg[N],u,v,head[N],cnt=1;
bool vis[N];
struct edge{
int to,nxt;
}e[N<<1];
void dfs(int u,int pre){
vis[u]=1;
for(int i=head[u];i;i=e[i].nxt)
if(i!=pre&&e[i].to!=v){
if(!vis[e[i].to])dfs(e[i].to,i^1);else{puts("Yes");exit(0);}
}
vis[u]=0;
}
int main(){
scanf("%d%d",&n,&m);
while(m--){
scanf("%d%d",&u,&v);
e[++cnt]=(edge){v,head[u]},head[u]=cnt;
e[++cnt]=(edge){u,head[v]},head[v]=cnt;
++deg[u],++deg[v];
}
for(int i=1;i<=n;++i)if(deg[i]&1)return puts("No"),0;
if(*std::max_element(deg+1,deg+n+1)>4)return puts("Yes"),0;
u=v=0;
for(int i=1;i<=n;++i)
if(deg[i]==4){if(!u)u=i;else if(!v)v=i;else return puts("Yes"),0;}
if(v)dfs(u,0);
return puts("No"),0;
}