Atcoder agc032C

这题是个大讨论题。
因为图连通且每条边恰经过一次,所以三个环可以拼成一个欧拉回路,因此可以尝试从欧拉回路的角度考虑。
原图必须存在欧拉回路,有奇点显然无解。
有度数 ≥ 6 \geq 6 6的点一定有解(任取一条从该点出发的回路,至少经过该点 3 3 3次,每次即为一个环)。
否则若度数全为 2 2 2或仅有一点度数为 4 4 4显然无解。
还可以发现若存在至少 3 3 3个度数为 4 4 4的点也一定有解(设三个点为A,B,C,同样任取一条点A出发的欧拉回路,若出现环套环就可以构造,否则一定形如A->B->C->A->B->C->A,可以构造出A->B->A,B->C->B,C->A->C的三个环)。
那现在只剩恰有两个度为 4 4 4的点的情况,这种情况下可以将度为 2 2 2的点缩起来,有解当且仅当存在自环。
时间复杂度 O ( N + M ) \mathcal O(N+M) O(N+M)

#include 
 
using namespace std;
 
struct Edge {
  int t,next;
  Edge() {}
  Edge(int a,int b):t(a),next(b) {}
};
 
Edge e[200005];
int head[100005],d[100005],rt1,rt2;
 
void dfs(int x,int fa) {
  for(int i=head[x];i;i=e[i].next)
    if (e[i].t!=fa) {
    	int u=e[i].t;
    	if (d[u]==2) dfs(u,x);
    	else if (u==rt1) {
    		puts("Yes");
    		exit(0);
		}
	}
}
 
int main() {
  int n,m;
  scanf("%d%d",&n,&m);
  for(int i=1;i<=m;i++) {
  	int x,y;
  	scanf("%d%d",&x,&y);
  	e[2*i-1]=Edge(y,head[x]);
  	head[x]=2*i-1;
  	e[2*i]=Edge(x,head[y]);
  	head[y]=2*i;
  	d[x]++;d[y]++;
  }
  for(int i=1;i<=n;i++)
    if (d[i]&1) {
    	puts("No");
    	return 0;
	}
  int cnt=0;
  for(int i=1;i<=n;i++)
    if (d[i]>=6) {
    	puts("Yes");
    	return 0;
	}
	else if (d[i]==4) cnt++;
  if (cnt<2) {
  	puts("No");
  	return 0;
  }
  if (cnt>2) {
  	puts("Yes");
  	return 0;
  }
  for(int i=1;i<=n;i++)
    if (d[i]==4) {
    	if (!rt1) rt1=i; else rt2=i;
	}
  dfs(rt1,0);
  puts("No");
  return 0;
}

你可能感兴趣的:(atcoder,集训队作业,图论)