Codeforces 527E Data Center Drama(欧拉回路)
题意:
给定一个无向图连通图,把这个的无向边变成有向边,并添加最少的有向边使这个图每个结点的出度为偶数。
Solution:
题目很长,并且很多条件说的不太直接,确实不太好懂。
首先先看得到的无向图,是不是可以不加边就满足题目要求。
可以想到对于一个无向图,当所有点的度数为偶数时,图中存在欧拉回路。那么对于一个存在欧拉路的无向图似乎可以以某种方式构造出满足条件的有向边。假设图中有欧拉回路1 2 3 4 1, 可以构造边2->1,2->3,4->3,4->1满足条件。
而对于不存在欧拉回路的图,可以在度数为奇数的两个节点间加一条边,或者添加自环使图中构成欧拉回路。
用邻接表会超时,用set维护边集,每次用过的边删除,能极大地节省时间。
找到欧拉路后,用上面的方法构造有向边输出就好了。
#include <bits/stdc++.h> using namespace std; const int MAXN = 1000009; int deg[MAXN], n, m, nCnt; vector<int > ans; multiset <int> G[MAXN]; inline void EulerianP (int x) { while (!G[x].empty() ) { int v = *G[x].begin(); G[x].erase (G[x].begin() ); G[v].erase (G[v].find (x) ); EulerianP (v); } ans.push_back (x); } int main() { scanf ("%d %d", &n, &m); for (int i = 1, u, v; i <= m; i++) { scanf ("%d %d", &u, &v); G[u].insert (v), G[v].insert (u); deg[u]++, deg[v]++; nCnt ++; } vector<int> s; for (int i = 1; i <= n; i++) if (deg[i] & 1) s.push_back (i); for (int i = 0; i < int (s.size() - 1); i += 2) G[s[i]].insert (s[i + 1]), G[s[i + 1]].insert (s[i]), nCnt ++; if (s.size() & 1) nCnt ++; nCnt += nCnt & 1; EulerianP (1); printf ("%d\n", nCnt); for (int i = 0; i < (int) ans.size() - 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 (ans.size() % 2 == 0) puts ("1 1"); }