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