Files
python/TangDou/AcWing/EulerPath/1184.cpp
HuangHai 1f397eca87 'commit'
2025-08-30 18:35:01 +08:00

100 lines
3.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include <bits/stdc++.h>
using namespace std;
const int N = 100010, M = 400010;
int T; // 1:无向图,2:有向图
int n, m; // n个节点,m条边
int din[N], dout[N]; // 入度,出度,如果是无向图,则din[u]+dout[u]=u点的度
int cnt, ans[M]; // 欧拉回路路径
// 链式前向星
int e[M], h[N], idx, w[M], ne[M];
void add(int a, int b, int c = 0) {
e[idx] = b, ne[idx] = h[a], w[idx] = c, h[a] = idx++;
}
int st[M]; // 某条边是否已访问过
// 1、无向图
void dfs1(int u) {
for (int i = h[u]; ~i; i = h[u]) {
h[u] = ne[i];
if (st[i]) continue; // 这个st[i]是给成对变换的无向图专用的,因为一边走一边删边,有向图的边都删除掉了,还记录啥走没走过,只有无向图才有这个,因为成对变换的边还没有删除掉,需要标识一下
// st[i] = 1, st[i ^ 1] = 1; // 无向图,成对变换的边也标识为已使用过
st[i ^ 1] = 1; // 无向图,成对变换的边也标识为已使用过
// 本题的特殊要求
int t = i / 2 + 1; // 无向图计算边号,注意i从0开始,所以需要除2再加1
if (i & 1) t = -t; // 偶数边u->v,奇数边v->u,题目要求v->u输出一个负号
// 注意是回溯时再记录,题解中有论述原因
dfs1(e[i]);
// 记录路径
ans[++cnt] = t;
}
}
// 2、有向图
void dfs2(int u) {
for (int i = h[u]; ~i; i = h[u]) {
h[u] = ne[i];
int t = i + 1; // 有向图计算边号,注意i从0开始,所以加1
// 注意是回溯时再记录,题解中有论述原因
dfs2(e[i]);
// 记录路径
ans[++cnt] = t;
}
}
int main() {
scanf("%d%d%d", &T, &n, &m); // 图的类型
memset(h, -1, sizeof h); // 链式前向星
for (int i = 0; i < m; i++) { // 后面的m条数是有用的,如果路径中最终的数量小于m,表示未能找到欧拉回路,不能用while(m--)替换
int a, b;
scanf("%d%d", &a, &b);
add(a, b);
if (T == 1) add(b, a);
din[b]++, dout[a]++; // 有向图:记录入度和出度;无向图:D(u)指经过u的无向边数量=din[u]+dout[u]
}
if (T == 1) {
for (int i = 1; i <= n; i++)
if ((din[i] + dout[i]) & 1) { // 无向图中,如果某个点的度是奇数,则不存在欧拉回路
puts("NO");
return 0;
}
} else {
for (int i = 1; i <= n; i++)
if (din[i] != dout[i]) { // 有向图中,如果某个点的入度与出度不等,则不存在欧拉回路
puts("NO");
return 0;
}
}
// 开始找欧拉回路
for (int u = 1; u <= n; u++)
// 举例:如果是两个欧拉回路图,那么两者之间彼此不连通,此时也不欧拉回路,我们找到一个非独立点开始出发,找出所有的边,
// 再通过检查边的数量与真实边的数量对比,才能真正知道是不是存在欧拉回路
if (~h[u]) {
if (T == 1)
dfs1(u);
else if (T == 2)
dfs2(u);
break;
}
// 如果找到的欧拉回路路径条数小于总边数m,表示没有找出全部边,说明无欧拉回路
if (cnt < m) {
puts("NO");
return 0;
}
// 存在欧拉回路
puts("YES");
// 逆序输出序列
for (int i = cnt; i; i--) printf("%d ", ans[i]);
return 0;
}