CF gym 102082 E Eulerian Flight Tour题解

89 篇文章 1 订阅

CF gym 102082 E Eulerian Flight Tour题解

一题比较繁琐的构造题。

首先存在欧拉回路的充要条件是每一个点的度数都为偶数,且图联通。

若原图本来就是联通的,我们就只需要是每一个点的度数都为偶数就可以了。

我们先建除一个补图。我们可以跑一个原图的dfs 树出来,然后从下往上,若以 i i i为根的子树内有奇数个奇数度数的点,就添加 i i i到它父亲的边。

若根有奇数个,则无解。

若不是,就从两个联通块内选出两个代表,向外连边。最后在把每一个联通快连接成一个环就行了(两个的情况比较特殊,需要两个联通块有一个不是”团“)

/*
{
######################
#       Author       #
#        Gary        #
#        2020        #
######################
*/
//#pragma GCC target ("avx2")
//#pragma GCC optimization ("O3")
//#pragma GCC optimization ("unroll-loops")
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
int n,m;
vector<mp> ans;
bool edge[101][101],vis[101],deg[101];
void erro(){
	cout<<"-1\n";
	exit(0);
}
int dfs(int now,int pre=0){
	int have=deg[now];
	vis[now]=1;
	rb(i,1,n) if(edge[now][i]&&!vis[i]) {have+=dfs(i,now);}	
	if(have&1){
		if(!pre) erro();
		ans.PB(II(now,pre));
	}
	return have;
} 
int fa[101];
int root(int x){
	return fa[x]=(fa[x]==x? x:root(fa[x]));
}
void merge(int u,int v){
	assert(edge[u][v]==0);
	edge[u][v]=edge[v][u]=1;
	fa[root(u)]=root(v);
}
void solve1(){
	int A,B=0;//选择两个作为两个联通快代表
	A=root(1);
	rb(i,1,n) if(root(i)!=root(1)) B=root(i);
	assert(B!=0);
	vector<int> v;
	rb(i,1,n) if(deg[i]) v.PB(i);
	vector<int> forA,forB;
	for(auto it:v){
		if((it==A||it==B)&&deg[A]&&deg[B]) continue;
		if(root(it)==A){
			forB.PB(it);
		}
		else{
			forA.PB(it);
		}
	} 
	if(deg[A]&&deg[B]){
		merge(A,B);
		ans.PB(II(A,B));
	}
	for(int i=forB.size()&1;i+1<forB.size();i+=2){
		ans.PB(II(B,forB[i]));
		ans.PB(II(B,forB[i+1]));
		merge(B,forB[i]);
		merge(B,forB[i+1]);
	}
	for(int i=forA.size()&1;i+1<forA.size();i+=2){
		ans.PB(II(A,forA[i]));
		ans.PB(II(A,forA[i+1]));
		merge(A,forA[i]);
		merge(A,forA[i+1]);
	}
	if(forB.size()&1){
		ans.PB(II(forB[0],forA[0]));
		merge(forB[0],forA[0]);
	}
	vector<int> cycle;
	rb(i,1,n)
		if(root(i)==i)
			cycle.PB(i);
	if(cycle.size()==2){
		bool ok=0;
		rb(i,1,n)
			rb(j,1,n){
				if(ok) break;
				if(!edge[i][j]&&i!=j){
					if(root(i)==root(j)){
						ok=1;
						ans.PB(II(i,j));
						if(root(i)==cycle[0]){
							ans.PB(II(i,cycle[1]));
							ans.PB(II(j,cycle[1]));
						}
						else{
							ans.PB(II(i,cycle[0]));
							ans.PB(II(j,cycle[0]));
						}
						break;
					}
				}
			}
		if(!ok) erro();
	}
	if(cycle.size()>2){
		cycle.PB(cycle[0]);
		for(int i=0;i+1<cycle.size();++i){
			ans.PB(II(cycle[i],cycle[i+1]));
		}
	}
	cout<<ans.size()<<endl;
	for(auto& it:ans){
		if(it.FIR>it.SEC) swap(it.FIR,it.SEC);
		assert(it.FIR<it.SEC);
		printf("%d %d\n",it.FIR,it.SEC);
	}
}
int main(){
	scanf("%d%d",&n,&m);
	rb(i,1,m){
		int ai,bi;
		scanf("%d%d",&ai,&bi);
		edge[ai][bi]=edge[bi][ai]=1;
		deg[ai]^=1;
		deg[bi]^=1;
	}
	bool cnt=0;
	rb(i,1,n) cnt^=deg[i];
	if(cnt) erro();
	rb(i,1,n) fa[i]=i;
	rb(i,1,n)
		rb(j,1,n) if(edge[i][j]) fa[root(i)]=root(j);
	rb(i,1,n){
		if(root(i)!=root(1)){
			solve1();
			return 0;
		}
	}
	rb(i,1,n)
		rb(j,1,n)
			edge[i][j]^=1;
	rb(i,1,n)
		if(!vis[i])
			dfs(i);
	cout<<ans.size()<<endl;
	for(auto& it:ans){
		if(it.FIR>it.SEC) swap(it.FIR,it.SEC);
		assert(it.FIR<it.SEC);
		printf("%d %d\n",it.FIR,it.SEC);
	}
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值