题解:P4038 [CERC 1995] John's Trip
题意
给定一张无向图,求这张图是不是 欧拉图; 如果有解,输出走过街道编号字典序最小的方案。
:::warning[注意]{open}
- 行末不得有空格。
- 输入一张图结束的标号是
0\;0 ,输入数据结束再跟一个0\;0 。 - 起点是输入第一条街道连接的两个顶点中编号较小的路口处。
- 在整个输入数据中,最多有
1995 条街,最多44 个路口。 :::
思路
这题的实现难点是欧拉回路和 DFS。
对于欧拉回路,只要判断每个结点的度是否均为偶数; 对于 DFS,因为数据小,只要用邻接表存储图(一个结点的邻接表应以连边编号为关键字,对节点进行排序),再普通跑一遍就行了。
主要坑点就是:输入很怪异,输出很坑。
代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
struct edge {
int to, id;
edge(int t, int i) : to(t), id(i) {}
// 按边编号从小到大排序,保证字典序最小
bool operator<(const edge& other) const {
return id < other.id;
}
};
const int MAXN = 50;
vector<edge> g[MAXN];
bool vis[2005];
vector<int> ans;
int du[MAXN];
void dfs(int u) {
for (auto &e : g[u]) {
int v = e.to;
int id = e.id;
if (!vis[id]) {
vis[id] = true;
dfs(v);
ans.push_back(id);
}
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int x, y, z;
while (cin >> x >> y) {
if (x == 0 && y == 0) break;
for (int i = 0; i < MAXN; ++i) {
g[i].clear();
du[i] = 0;
}
for (int i = 0; i <= 1995; ++i) vis[i] = false;
ans.clear();
int st = min(x, y);
cin >> z;
g[x].emplace_back(y, z);
g[y].emplace_back(x, z);
du[x]++; du[y]++;
while (cin >> x >> y) {
if (x == 0 && y == 0) break;
cin >> z;
g[x].emplace_back(y, z);
g[y].emplace_back(x, z);
du[x]++; du[y]++;
}
bool ok = true;
for (int i = 1; i <= 44; ++i) {
if (du[i] % 2 != 0) {
ok = false;
break;
}
}
if (!ok) {
cout << "Round trip does not exist.\n";
continue;
}
for (int i = 1; i <= 44; ++i) {
sort(g[i].begin(), g[i].end());
}
dfs(st);
for (long long i = ans.size() - 1; i >= 1; --i) {
cout << ans[i] << " ";
}
cout << ans[0] << "\n";
}
return 0;
}
本体代码写完后经过了 AI 润色。