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)&°[A]&°[B]) continue;
if(root(it)==A){
forB.PB(it);
}
else{
forA.PB(it);
}
}
if(deg[A]&°[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;
}