1 条题解
-
0
思路与算法
无向图检查非零度顶点连通及所有度数为偶;有向图检查入度等于出度并覆盖全部非零度边。选择有边起点,显式栈Hierholzer消耗唯一边号,退栈收集后逆序输出。无向边反向经过时取负编号。
正确性说明
度条件是欧拉回路必要条件;在非零度部分连通的条件下也充分。有向平衡且弱连通时所有有边部分属于同一可行欧拉结构。Hierholzer每次用未用边延伸,局部闭游走在退栈时拼成全局回路;检查最终恰有m边也同时排除分离的回路。
复杂度
读入、度数组和游标初始化O(n+m),每个邻接项扫描一次,总O(n+m)时间与空间。
易错点
孤点不影响有边部分;m=0输出YES及空方案。自环无向度数增加2,重边用不同编号。特判验证符号、连续性、闭合及每边恰一次,不能固定比较样例路径。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t, n, m; cin >> t >> n >> m; vector<vector<pair<int, int>>> g(n); vector<int> in(n), out(n); for (int i = 1, u, v; i <= m; i++) { cin >> u >> v; --u; --v; g[u].push_back({v, i}); out[u]++; in[v]++; if (t == 1) { g[v].push_back({u, -i}); out[v]++; in[u]++; } } for (int i = 0; i < n; i++) if ((t == 1 && out[i] % 2) || (t == 2 && out[i] != in[i])) { cout << "NO\n"; return 0; } int root = 0; while (root < n && !out[root]) root++; if (root == n) { cout << "YES\n\n"; return 0; } vector<int> used(m + 1), pos(n), st(1, root), edge, ans; while (!st.empty()) { int u = st.back(); while (pos[u] < (int)g[u].size() && used[abs(g[u][pos[u]].second)]) pos[u]++; if (pos[u] < (int)g[u].size()) { auto e = g[u][pos[u]++]; used[abs(e.second)] = 1; st.push_back(e.first); edge.push_back(e.second); } else { st.pop_back(); if (!edge.empty()) { ans.push_back(edge.back()); edge.pop_back(); } } } if ((int)ans.size() != m) { cout << "NO\n"; return 0; } reverse(ans.begin(), ans.end()); cout << "YES\n"; for (int i = 0; i < m; i++) cout << ans[i] << (i + 1 == m ? '\n' : ' '); }
- 1