有人说,图论的起源,就是源于欧拉图(千万别看成柏拉图)——题记
首先,先要讲一些有必要知道的东西:当然,我在这里也写过,这里再给出一些拓展的内容
欧拉通路: 通过图中每条边且只通过一次,并且经过每一顶点的通路
欧拉回路: 通过图中每条边且只通过一次,并且经过每一顶点的回路
有向图的基图:忽略有向图所有边的方向,得到的无向图称为该有向图的基图。
欧拉图与半欧拉图:
- 欧拉图指的是给出的图G<V, E>,满足所有的点V联通,并且每个点的度都是偶数,则图中的所有的边都可以一笔画经过,并且回到起始点,则我们说给出的图G是欧拉图;
- 半欧拉图的性质与欧拉图相似,但是它可以首尾不相连接,也就是这幅图是欧拉通路,满足图中的所有的边都可以一笔画经过,但是不要求回归起点。
无向图的欧拉图判定与有向图的欧拉图判定
无向图
设G是连通无向图,则称经过G的每条边一次并且仅一次的路径为欧拉通路;
如果欧拉通路是回路(起点和终点是同一个顶点),则称此回路是欧拉回路
具有欧拉回路的无向图G成为欧拉图
有向图
(1)设D是有向图,D的基图连通,则称经过D的每条边一次并且仅有一次的有向路径为 有向欧拉通路
(2)如果有向欧拉通路是有向回路,则称此有向回路为 有向欧拉回路
(3)具有有向欧拉回路的图D称为有向欧拉图
定理(无向图)
无向图G存在欧拉通路的充要条件是:G为连通图,并且G仅有两个奇度结点(度数为奇数的顶点)或者无奇度结点。
推论(无向图)
(1) 当G是仅有两个奇度结点的连通图时,G的欧拉通路必以此两个结点为端点;
(2)当G是无奇度结点的连通图时,G必有欧拉回路
(3)G为欧拉图(存在欧拉回路)的充分必要条件是 G为无奇度结点的连通图
定理(有向图)
有向图D存在欧拉通路的充要条件是:D为有向图,D的基图连通,并且所有顶点的出度与入度相等;或者 除两个顶点外,其余顶点的出度与入度都相等,而这两个顶点中一个顶点的出度与入度之差为1,另一个顶点的出度与入度之差为-1.
推论(有向图)
(1)当D除出、入度之差为1,-1的两个顶点之外,其余顶点的出度与入度相等时,D的有向欧拉通路必以出、入度之差为1的顶点作为始点,以出、入度之差为-1的顶点作为终点。
(2)当D的所有顶点的出、入度都相等时,D中存在有向欧拉回路。
(3)有向图D为有向欧拉图的充要条件是 D的基图为连通图,并且所有顶点的出、入度都相等。
欧拉图(半欧拉图)的路径求解
先举例一张图:
我们直接从图上来看,我们正确的跑法肯定是“3--1--2--3--4--5--6--4”或者是“4--6--5--4--3--2--1--3”等等很多种方案,我分别列举了输出字典序最小与最大的情况。
这样的话,我们可以直接dfs,我们直接找到一个起点并且往下跑。但是,这可能存在一个问题,譬如说我们的3号结点,这次想直接跑4号结点,那样就会产生最坏的情况。所以,这告诉了我们如果没有其他路径,最好不要去跑桥(3--4这条边就是桥)。
我们这里用的是dfs深搜来解决这个问题,这里是dfs加上栈的维护,相当于是起到了一个“修复”的作用。我们这次从3往4号结点跑,因为会回溯回来再重新跑(相当于是更正修复),所以dfs搜到的是“3--4--5--6--4--(回溯)--1--2--3”此时我们的栈会变成:从栈底往栈顶来看“4 6 5 4 3 2 1 3”。此时,就是正确的欧拉通路了。
dfs的函数过程是:
void dfs(int u)
{
for(int i=head[u], v; ~i; i=edge[i].nex)
{
if(vis[i]) continue;
vis[i] = true;
v = edge[i].to;
dfs(v);
}
Stap[++Stop] = u;
}
当然,这个剪枝,虽然是用了vis剪枝了,但是由于每条边只用一次,我们可以用一种叫做当前弧优化的东西来剪枝(可以参考Dinic的当前弧优化来解决这个问题)。
void dfs(int u)
{
for(int i=head[u], v; ~i; i=head[u])
{
v = edge[i].to; head[u] = edge[head[u]].nex;
dfs(v);
}
Stap[++Stop] = u;
}
接下去,换一种比较简短的写法,与上面这个作用一样:
void dfs(int u)
{
while(~head[u])
{
v = edge[i].to; head[u] = edge[head[u]].nex;
dfs(v);
}
Stap[++Stop] = u;
}
放一道判断是否是欧拉回路的题:
欧拉回路
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
//#define INF 10000007.
#define eps 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e3 + 7;
int N, M, du[maxN], root[maxN];
int fid(int x) { return x == root[x] ? x : root[x] = fid(root[x]); }
inline void init()
{
for(int i=1; i<=N; i++)
{
du[i] = 0;
root[i] = i;
}
}
int main()
{
while(scanf("%d", &N) && N)
{
scanf("%d", &M);
init();
for(int i=1, u, v, fu, fv; i<=M; i++)
{
scanf("%d%d", &u, &v);
du[u]++; du[v]++;
fu = fid(u); fv = fid(v);
if(fu ^ fv) { root[fu] = fv; }
}
bool ok = true; int cnt = 0;
for(int i=1; i<=N; i++)
{
if(i == fid(i))
{
cnt++;
if(cnt > 1)
{
ok = false;
break;
}
}
if(du[i] & 1) { ok = false; break; }
}
printf("%d\n", ok);
}
return 0;
}
再放一道输出欧拉回路路径的题:
Watchcow
给出N个点,M条边,并且呢,M条边要经过两次,一次是从u到v,那么下一次就不能走u到v了,只允许走v到u了。
其实题意已经帮你把欧拉图建好了,而且题目保证联通。
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <bitset>
//#include <unordered_map>
//#include <unordered_set>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
//#define INF 10000007.
#define eps 1e-7
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
#define MP(a, b) make_pair(a, b)
using namespace std;
typedef unsigned long long ull;
typedef unsigned int uit;
typedef long long ll;
const int maxN = 1e4 + 7, maxM = 5e4 + 7;
int N, M;
struct LSQXX
{
int head[maxN], cnt;
struct Eddge
{
int nex, to;
Eddge(int a=-1, int b=0):nex(a), to(b) {}
}edge[maxM << 1];
inline void addEddge(int u, int v)
{
edge[cnt] = Eddge(head[u], v);
head[u] = cnt++;
}
inline void _add(int u, int v) { addEddge(u, v); addEddge(v, u); }
int Stap[maxM << 1], Stop;
void dfs(int u)
{
int v;
while(~head[u])
{
v = edge[head[u]].to;
head[u] = edge[head[u]].nex;
dfs(v);
}
Stap[++Stop] = u;
}
inline void clear()
{
cnt = 0; Stop = 0;
for(int i=1; i<=N; i++) head[i] = -1;
}
} E;
struct Graph
{
int u, v;
Graph(int a=0, int b=0):u(a), v(b) {}
inline void In_Put() { scanf("%d%d", &u, &v); }
} G[maxM];
int main()
{
scanf("%d%d", &N, &M);
E.clear();
for(int i=1; i<=M; i++) { G[i].In_Put(); E._add(G[i].u, G[i].v); }
E.dfs(1);
for(int i=E.Stop; i; i--) printf("%d\n", E.Stap[i]);
return 0;
}
来源:CSDN
作者:Andres_Lionel
链接:https://blog.csdn.net/qq_41730082/article/details/104116029