概念
欧拉路径指一条所有边都经过且只有一次的路径
如果起点和终点相同就是欧拉回路
判定
有向图:所有点连通,且入度都等于出度,则有欧拉回路
无向图:所有点连通,且度数为偶数,则有欧拉回路
显然欧拉回路删掉一条边就是欧拉路径
那么欧拉路径中有且只有两个不符合欧拉回路要求的点,并且相连后就满足了
算法
求欧拉路径就把不满足的点连起来,求欧拉回路后删掉这条边就好了
无向图
\(dfs\),标记走过的边以及反边,走过就不走
每次回溯时记录边,这些边依次构成欧拉回路
有向图
边反向,\(dfs\)标记走过的边,每次回溯时记录边,这些边依次构成欧拉回路
都差不多,然后可以当前弧优化
正确性
除了第一个点外,其它的点\(dfs\)是一定是入边出边成对出现
所以第一次加入答案的边一定是第一个点的入边
回溯时这个点又会多走一条出边,那么下次加入的一定是又是这个点的入边
归纳下去,一定会形成一条回路
代码
\(UOJ\)模板
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
const int _(4e5 + 5);
typedef int Arr[_];
IL int Input(){
RG int x = 0, z = 1; RG char c = getchar();
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
return x * z;
}
Arr first, cur, vis, ans, rd, od;
int n, m, cnt, num;
struct Edge{
int to, next, id;
} edge[_];
IL void Add1(RG int u, RG int v, RG int id){
++rd[u], ++rd[v];
edge[cnt] = (Edge){v, first[u], id}, first[u] = cnt++;
edge[cnt] = (Edge){u, first[v], -id}, first[v] = cnt++;
}
IL void Dfs1(RG int u){
for(RG int &e = cur[u]; e != -1; e = edge[e].next){
if(vis[e]) continue;
RG int tmp = e; vis[e] = vis[e ^ 1] = 1;
Dfs1(edge[e].to);
ans[++num] = edge[tmp ^ 1].id;
if(e == -1) return;
}
}
IL void Work1(){
Fill(first, -1), n = Input(), m = Input();
for(RG int i = 1, u, v; i <= m; ++i) u = Input(), v = Input(), Add1(u, v, i);
for(RG int i = 1; i <= n; ++i){
cur[i] = first[i];
if(rd[i] & 1){
puts("NO");
return;
}
}
for(RG int i = 1; i <= n; ++i)
if(rd[i]){
Dfs1(i);
break;
}
if(num != m){
puts("NO");
return;
}
puts("YES");
for(RG int i = 1; i <= m; ++i) printf("%d ", ans[i]);
puts("");
}
IL void Add2(RG int u, RG int v, RG int id){
++rd[v], ++od[u];
edge[cnt] = (Edge){v, first[u], id}, first[u] = cnt++;
}
IL void Dfs2(RG int u){
for(RG int &e = cur[u]; e != -1; e = edge[e].next){
if(vis[e]) continue;
RG int tmp = e; vis[e] = 1;
Dfs2(edge[e].to);
ans[++num] = edge[tmp].id;
if(e == -1) return;
}
}
IL void Work2(){
Fill(first, -1), n = Input(), m = Input();
for(RG int i = 1, u, v; i <= m; ++i) u = Input(), v = Input(), Add2(v, u, i);
for(RG int i = 1; i <= n; ++i){
cur[i] = first[i];
if(rd[i] != od[i]){
puts("NO");
return;
}
}
for(RG int i = 1; i <= n; ++i)
if(od[i]){
Dfs2(i);
break;
}
if(num != m){
puts("NO");
return;
}
puts("YES");
for(RG int i = 1; i <= m; ++i) printf("%d ", ans[i]);
puts("");
}
int main(RG int argc, RG char *argv[]){
Input() == 1 ? Work1() : Work2();
return 0;
}