题意:
现有一张n个点m条边的无向图,你需要给这个无向图的所有边重新定向,使得新图所有点中,出度 = 入度的点尽可能地多,打印出任意一种可行的方案
solution:
首先,一张无向图中,度数为奇数的点一定是偶数个,因为无向图所有点的度数和一定是偶数
设度数为奇数的点有k个,分别是o1,o2,o3,...,ok
在图中新加入五向边(o1,o2),(o3,o4),(o5,o6),...,(ok-1,ok)
这样新图中所有点的度数均为偶数,一定存在欧拉回路
在这张图中跑欧拉回路算法,,求出欧拉回路,打印方案即可
欧拉回路朴素算法,,套圈法。。
任取一点开始随意dfs,找到一条从它出发并回到自身的路径,这样不能保证所有点都访问过
从这条路径上找,每找到一个还有边没访问过的点就把它另作起点重新dfs
处理欧拉回路时一遍处理一遍删边,复杂度O(m)
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<bitset>
#include<algorithm>
#include<cstring>
#include<map>
#include<stack>
#include<set>
#include<cmath>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;
const int maxn = 222;
const int maxm = maxn*maxn;
int n,m,T,cnt,vis,top,du[maxn],pre[maxm],q[maxn][maxn]
,num[maxm],to[maxm],bo[maxm],s[maxn],last[maxn];
void Add(int x,int y,int nu)
{
to[++cnt] = y;
pre[cnt] = last[x];
last[x] = cnt;
num[cnt] = nu;
}
void Dfs(int x,int fa)
{
q[fa][++q[fa][0]] = x;
int z = last[x];
while (bo[num[z]] == vis)
z = pre[z],last[x] = z;
bo[num[z]] = vis;
if (num[z] <= m)
printf("%d %d\n",x,to[z]);
if (to[z] != fa) Dfs(to[z],fa);
}
void Euler_cycle(int x)
{
while (du[x]) {
q[x][0] = 0;
Dfs(x,x);
queue <int> Q;
for (int i = 1; i <= q[x][0]; i++) {
du[q[x][i]] -= 2;
if (du[q[x][i]]) Q.push(q[x][i]);
}
while (!Q.empty()) {
int k = Q.front(); Q.pop();
if (!du[k]) continue;
Euler_cycle(k);
}
}
}
int main()
{
#ifdef DMC
freopen("DMC.txt","r",stdin);
#endif
cin >> T;
while (T--) {
scanf("%d%d",&n,&m);
for (int i = 1; i <= n; i++) du[i] = last[i] = 0;
cnt = 0; ++vis;
for (int i = 1; i <= m; i++) {
int x,y;
scanf("%d%d",&x,&y);
Add(x,y,i);
Add(y,x,i);
++du[x]; ++du[y];
}
int ans; ans = top = 0;
for (int i = 1; i <= n; i++)
if (du[i]&1) s[++top] = i;
else ++ans;
printf("%d\n",ans);
int tot = m;
for (int i = 1; i <= top; i += 2) {
++tot;
Add(s[i],s[i+1],tot);
Add(s[i+1],s[i],tot);
++du[s[i]]; ++du[s[i+1]];
}
for (int i = 1; i <= n; i++)
if (du[i]) Euler_cycle(i);
}
return 0;
}