1.【定义】
欧拉路我们将其称为是一个图中从某一节点 \(S\) 出发,恰好经过图中每条边各一次,但是可以重复经过图中节点的路。
欧拉回路就是指就是从某点 \(S\) 出发最后仍回到 \(S\) 的欧拉路。
存在欧拉路的图被称为欧拉图。
存在欧拉路但是不存在欧拉回路的图叫做半欧拉图。
2.【判定】
【欧拉图的判定】
一张无向图为欧拉图,仅当无向图连通,并且每个节点的度数为偶数。
证明: 等价于判定是否存在欧拉回路,而每条边都要经过,然后回到最开始等价于是进行出去与回来的反复操作,所以判定正确。
【欧拉路存在性判定】
一张无向图中存在欧拉路,仅当无向图连通,并且恰好只有两个节点 \(S\) 和 \(T\) 的度数为奇数其他均为偶数。
证明: 等价于是不在回到起点的欧拉回路,联合上面证明所以显然。
【半欧拉图的判定】
一张无向图是半欧拉图当且仅当这个图是连通的,并且恰好有 \(2\) 个奇度数节点。
证明: 等价于判断处在欧拉路。
【有向图欧拉图判定】
所有点属于一个强连通分量且每个顶点的入度和出度相同。
【有向图半欧拉图判定】
将所有有向边变成无向边时,所有点属于一个强连通分量。
最多只有一个顶点的出度与入度差为 \(1\) 。
最多只有一个顶点的入度与出度差为 \(1\) 。
所有其他顶点的入度与出度相同。
3.【题目】
P7771 【模板】欧拉路径
求有向图字典序最小的欧拉路径。
模板欧拉路,按照上面的方法模拟就是了。
const int N = 3e5;
int n, m, in[N], out[N], vis[N], ans[N], num, cur[N];
vector<int> ver[N];
void dfs(int x) {
for (int i = cur[x]; i < ver[x].size(); i = cur[x]) {
cur[x] = i + 1;
dfs(ver[x][i]);
}
ans[++num] = x;
}
signed main() {
n = read(), m = read();
for (int i = 1; i <= m; i++) {
int a = read(), b = read();
ver[a].push_back(b);
in[b]++;
out[a]++;
}
for (int i = 1; i <= n; i++)
sort(ver[i].begin(), ver[i].end());
int pd = 0, st = 1, en = 0;
for (int i = 1; i <= n; i++) {
if (in[i] == out[i])
continue;
else {
if (in[i] + 1 == out[i]) {
if (pd && st) {
printf("No\n");
return 0;
} else
st = i;
}
if (out[i] + 1 == in[i]) {
if (en) {
printf("No\n");
return 0;
} else
en = i;
}
pd = 1;
}
}
dfs(st);
for (int i = num; i; i--)
printf("%lld ", ans[i]);
printf("\n");
return 0;
}