题目链接:CodeForces-528C Data Center Drama
题意
给出一个无向图(连通,可能有重边和自环),要求加尽量少的边,并给每条边定向,使每个结点的入度和出度都是偶数。
思路
对于度数为奇数的结点,加边依次连接,例如结点$1,2,3,4$的度数为奇数,则连接$(1,2)$,$(3, 4)$,使所有结点度数都为偶数,则为欧拉图。
如果此时边数为奇数,则对任一结点加个自环,这样可以构造出偶数长度的欧拉回路。沿着欧拉回路每隔一条边反向一次,可令结点每一条入边和出边变成两条入边或两条出边,就满足了题目要求的每个结点的入度和出度都是偶数。
代码实现
#include <cstdio> #include <cstring> const int N = 100010, M = 500010; struct Edge { int to, nex; } edge[M]; int cnt_e, tot; int head[N], deg[N], ans[M]; 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) { // 求欧拉回路方案,存在ans中 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; dfs(v); } } ans[tot++] = u; // 要后序回溯时记录路径,不能前序记录 } int main() { int n, m; while (~scanf("%d %d", &n, &m)) { init(); int ans1 = 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]++; } int pre; tot = 0; for (int i = 1; i <= n; i++) { if (deg[i] & 1) { if (tot & 1) { add_edge(pre, i); add_edge(i, pre); ans1++; } else pre = i; tot++; } } if (ans1 & 1) { ans1++; add_edge(1, 1); } printf("%d\n", ans1); tot = 0; dfs(1); for (int i = 0; i < tot - 1; i++) { if (i & 1) printf("%d %d\n", ans[i], ans[i+1]); else printf("%d %d\n", ans[i+1], ans[i]); } if (!(tot & 1)) puts("1 1"); } return 0; }
原文地址:https://www.cnblogs.com/kangkang-/p/11380634.html
时间: 2024-10-07 14:32:39