vector<vector<int>> E(n); while (m--) { int u, v; cin >> u >> v; u--, v--; E[u].push_back(v); }
vector<int> deg(n); // in-degree 入度 for (int u = 0; u < n; ++u) { sort(E[u].begin(), E[u].end(), greater<>()); // 输出字典序最小 for (auto& v : E[u]) deg[v]++; }
int s = -1, t = -1, ok = true; for (int u = 0; u < n; ++u) { int d = E[u].size() - deg[u]; // out-in 出度-入度 if (d == 1) { if (~s) ok = false; // 至多一个顶点的出度与入度之差为 1 s = u; } elseif (d == -1) { if (~t) ok = false; // 至多一个顶点的入度与出度之差为 1 t = u; } elseif (d) ok = false; // 其他顶点的入度和出度相等 } if (s == -1) s = 0;
vector<int> path; auto dfs = [&](thisauto&& self, int u) -> void { while (!E[u].empty()) { auto v = E[u].back(); E[u].pop_back(); self(v); } path.push_back(u); }; if (ok) dfs(s);
if (path.empty()) { cout << "No\n"; } elsefor (auto& u : vector(path.rbegin(), path.rend())) { cout << u + 1 << " "; }
vector<vector<pair<int, int>>> E(n); for (int i = 0; i < m; ++i) { int u, v; cin >> u >> v; u--, v--; E[u].push_back({ v, i }); E[v].push_back({ u, i }); }
int ok = true; vector<int> s; for (int u = 0; u < n; ++u) { sort(E[u].begin(), E[u].end(), greater<>()); if (E[u].size() & 1) { s.push_back(u); } } if (s.size() > 2) ok = false; elseif (s.empty()) s.push_back(0); elsesort(s.begin(), s.end());
vector<int> path; vector<int> inpath(m); auto dfs = [&](thisauto&& self, int u) -> void { while (!E[u].empty()) { auto [v, id] = E[u].back(); E[u].pop_back(); if (inpath[id]) continue; inpath[id] = 1; self(v); } path.push_back(u); }; if (ok) dfs(s[0]);
if (path.empty()) { cout << "No\n"; } elsefor (auto& u : vector(path.rbegin(), path.rend())) { cout << u + 1 << "\n"; }
关于为什么要回溯时入栈,倒着输出,而不是边遍历边输出
对比以下两种写法:
(一)
1 2 3 4 5 6 7 8 9 10
voiddfs(int u){ path.push_back(u); while (!E[u].empty()) { auto v = E[u].back(); E[u].pop_back(); dfs(v); } }
for (auto& u : path) printf("%d ", u);
(二)
1 2 3 4 5 6 7 8 9 10 11
voiddfs(int u){ while (!E[u].empty()) { auto v = E[u].back(); E[u].pop_back(); dfs(v); } path.push_back(u); }
reverse(path.begin(), path.end()); for (auto& u : path) printf("%d ", u);
先给 Hack 数据:
1 2 3 4 5
3 4 1 2 2 1 2 3 3 2
第一种的代码跑出来是 1 2 1 3 2,显然是错误的。
分析 DFS 的过程:
1 2 3 4 5 6 7 8 9 10
dfs(1): 包含边 2 dfs(2): 包含边 1 3 dfs(1): 没有边 end dfs(3): 包含边 2 dfs(2): 没有边 end end end end