题目链接:CodeForces-723E One-Way Reform
题意
给出一个无向图,让我们给边定向,使入度等于出度的结点最多。
思路
首先入度等于出度的结点其度数肯定是偶数的,那么能否让所给的图中所有度数为偶的结点都满足要求?
考虑欧拉图,下面是与欧拉图与此题有关的定义和性质:
通过图中所有边一次且仅一次的回路称为欧拉回路。
具有欧拉回路的图称为欧拉图。
一个无向图存在欧拉回路,当且仅当该图所有结点度数都为偶数,且该图是连通图。
一个有向图存在欧拉回路,当且仅当该图所有结点的入度等于出度,且该图是连通图。
显然欧拉图中按欧拉回路给每条边定向能令每个结点的入度都等于出度。
一个图中度数为奇的结点个数一定是偶数,我们新加一个结点$n+1$,所有度数为奇的结点和$n+1$连边,这样新图中所有结点度数为偶,则为欧拉图。(题目给出的图不一定连通,那我们构造出来的可能是多个欧拉图,不影响答案正确性。)
dfs跑出欧拉回路给每条边定向,输出属于原图的边即可。原图中度数为偶的结点的连边都没有改动,所以这样构造出来的方案能令原图所有度数为偶的结点满足入度等于出度。
时间复杂度$O(E)$。
代码实现
#include <cstdio> #include <cstring> const int N = 210, M = N * N + N; struct Edge { int to, nex; } edge[M]; int n, cnt_e; int head[N], deg[N]; bool vis[M]; void add_edge(int u, int v) { edge[++cnt_e].to = v; edge[cnt_e].nex = head[u]; head[u] = cnt_e; } void init() { cnt_e = 1; memset(head, 0, sizeof(head)); memset(deg, 0, sizeof(deg)); memset(vis, 0, sizeof(vis)); } void dfs(int u) { for (int i = head[u]; i; i = head[u]) { head[u] = edge[i].nex; if (!vis[i|1]) { vis[i|1] = true; int v = edge[i].to; if (u != n + 1 && v != n + 1) printf("%d %d\n", u, v); dfs(v); } } } int main() { int t, m; scanf("%d", &t); while (t--) { init(); scanf("%d %d", &n, &m); for (int i = 0, u, v; i < m; i++) { scanf("%d %d", &u, &v); add_edge(u, v); add_edge(v, u); deg[u]++, deg[v]++; } for (int i = 1; i <= n; i++) { if (deg[i] & 1) { add_edge(i, n + 1); add_edge(n + 1, i); deg[n+1]++; } } printf("%d\n", n - deg[n+1]); for (int i = 1; i <= n; i++) dfs(i); } return 0; }