|
|
#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;
|
|
|
} |