定义
欧拉回路:从图上一个点u出发不重复地经过每一条边后,再次回到点u的一条路径。
欧拉路径:从图上一个点u出发不重复地经过每一条边的一条路径(不必回到点u)。
欧拉图即存在欧拉回路的图,半欧拉图即存在欧拉路径的图。
而要求每个点只走一次的模型是哈密顿环。
定理
(1)无向图欧拉回路的判定:图G为连通图,所有顶点的度为偶数。
(2)无向图欧拉路径的判定:图G为连通图,除有2个顶点度为奇数外,其他顶点度都为偶数。
(3)有向图欧拉回路的判定:图G的基图联通(忽略有向图所有边的方向),所有顶点的入度等于出度。
(4)有向图欧拉路径的判定:图G的基图联通,存在顶点u的入度比出度小1,v入度比出度大一,其余所有顶点的入度等于出度。(此时u即路径的起点,v即终点)
其他定理
(5)无向图为(半)欧拉图时,只需用1笔画成;无向图为非(半)欧拉图时,即奇点(度为奇数的点)数k>2,需用k/2笔画成。
(6)可以用加边的方式把一个非欧拉图变成欧拉图。对于无向图来说,每个奇点都需加一个度,加的边为 奇点数/2 ;对于有向图来说,每个点都需加上入度与出度之差,加的边数为每个点入度与出度之差的绝对值之和再除以2。
一个图的奇点数一定是偶数。
求欧拉回路和欧拉路径
在无向图中实现
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
int G[100][100], n, du[100], ans[10000], temp, len;
void dfs(int k)
{
for(int i = 1; i <= 100; i++){
if(G[k][i]){
G[k][i] = 0;
G[i][k] = 0;
dfs(i);
}
}
ans[len++] = k; //保存路径
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++){
int x, y;
scanf("%d %d", &x, &y);
du[x]++; //x的度数++
du[y]++;
G[x][y] = 1; //建图
G[y][x] = 1;
}
for(int i = 1; i <= 100; i++){
if(du[i] % 2 == 1) //如果说度数为奇数
temp++;
}
if(temp != 0 && temp != 2) printf("既不是欧拉回路也不是欧拉路径\n");
if(temp == 0){ //是欧拉回路,所有的度数都为偶数
for(int i = 1; i <= 100; i++){
if(du[i] != 0){ //随便找到一个点
dfs(i);
break;
}
}
}
if(temp == 2){ //是欧拉路径, 因为正好就有两个度数为奇数的点
for(int i = 1; i <= 100; i++){
if(du[i] % 2 == 1){ //因为,欧拉路径的起点应该是度数为奇数的点,所以遍历找到一个度数为奇数的点
dfs(i);
break;
}
}
}
for(int i = len - 1; i >= 1; i--){
printf("%d", ans[i]);
}
return 0;
}
在有向图中实现
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
struct node
{
int to; //出度
int from; //入度
}du[100];
int G[100][100], n, ans[10000], temp, len, a, b;
void dfs(int k) //
{
for(int i = 1; i <= 100; i++){
if(G[k][i]){
G[k][i] = 0;
dfs(i);
}
}
ans[len++] = k; //保存路径
}
int main()
{
cin>>n;
for(int i = 1; i <= n; i++){
int x, y;
scanf("%d %d", &x, &y); //从x指向y
du[x].to++; //x的出度+1
du[y].from++; //y的入度+1
G[x][y] = 1; //建图,从x指向y
}
for(int i = 1; i <= 100; i++){
if(du[i].to != du[i].from) temp++; //入度数不等与出度数
else if(du[i].to - du[i].from == 1) a++; //出度比入度多1
else if(du[i].from - du[i].to == 1) b++; //入度比出度多1
}
if(temp != 0 && temp != 2) printf("既不是欧拉回路也不是欧拉路径\n");
if(temp == 0){ //是欧拉回路,所有的入度都等于出度
for(int i = 1; i <= 100; i++){
if(du[i].to != 0){ //随便找到一个点
dfs(i);
break;
}
}
}
if(temp == 2 && a == 1 && b == 1){ //是欧拉路径, 因为仅 i 点的出度比入度多 1 , j 点的的入度比出度多 1 。
for(int i = 1; i <= 100; i++){
if(du[i].to - du[i].from == 1){ //因为,欧拉路径的起点应该是出度比入度多 1
dfs(i);
break;
}
}
}
for(int i = len - 1; i >= 1; i--){
printf("%d", ans[i]);
}
return 0;
}