由于自环存在,讨论得比较繁琐。
先随便给边定向,根据每个节点的入/出边数目奇偶性可以分为
4
4
4种情况,其中
(
0
,
1
)
(0,1)
(0,1)和
(
1
,
0
)
(1,0)
(1,0)的点数奇偶性相同。对于
(
0
,
1
)
(0,1)
(0,1)或
(
1
,
0
)
(1,0)
(1,0),必须增加至少
1
1
1条连到它的边,我们让它们两两匹配即可。这样只剩
(
0
,
0
)
(0,0)
(0,0)和
(
1
,
1
)
(1,1)
(1,1),由于翻转一条两端为
(
1
,
1
)
(1,1)
(1,1)路径不会改变入边数目和的奇偶性,因此若有奇数个
(
1
,
1
)
(1,1)
(1,1),还需补一个自环。
现在只有若干个
(
0
,
0
)
(0,0)
(0,0)和偶数个
(
1
,
1
)
(1,1)
(1,1),直接用生成树构造即可。
时间复杂度
O
(
n
+
m
)
\mathcal O(n+m)
O(n+m)。
#include <bits/stdc++.h>
#define last last2
using namespace std;
struct Edge {
int t,next;
Edge() {}
Edge(int a,int b):t(a),next(b) {}
};
Edge e[1000005];
int head[100005];
bool col[500005];
bool vis[100005],in[100005],out[100005];
vector <int> vt;
bool dfs(int x) {
vis[x]=1;
bool v=in[x];
for(int i=head[x];i;i=e[i].next)
if (!vis[e[i].t]) {
int u=e[i].t;
if (dfs(u)) {
col[(i+1)>>1]=1;
v^=1;
}
}
return v;
}
int main() {
int n,m;
scanf("%d%d",&n,&m);
int k=0;
for(int i=1;i<=m;i++) {
int x,y;
scanf("%d%d",&x,&y);
if (x==y) {
vt.push_back(x);
in[x]^=1;out[x]^=1;
}
else {
k++;
e[2*k-1]=Edge(y,head[x]);
head[x]=2*k-1;
e[2*k]=Edge(x,head[y]);
head[y]=2*k;
in[y]^=1;out[x]^=1;
}
}
int last=0,s=0,id=0;
for(int i=1;i<=n;i++)
if (in[i]^out[i]) {
if (last) {
k++;
e[2*k-1]=Edge(i,head[last]);
head[last]=2*k-1;
e[2*k]=Edge(last,head[i]);
head[i]=2*k;
in[i]^=1;out[last]^=1;
last=0;
}
else last=i;
}
for(int i=1;i<=n;i++)
if (in[i]&&out[i]) {
s^=1;
id=i;
}
if (s) {
vt.push_back(id);
in[id]^=1;out[id]^=1;
}
dfs(1);
printf("%d\n",k+(int)vt.size());
for(int i=1;i<=k;i++)
if (col[i]) printf("%d %d\n",e[2*i-1].t,e[2*i].t);
else printf("%d %d\n",e[2*i].t,e[2*i-1].t);
for(int i=0;i<vt.size();i++) printf("%d %d\n",vt[i],vt[i]);
return 0;
}