算法 {
欧拉回路(有向图)
定义
#欧拉回路#
给定有向图G, 如果存在一个环x->...->x
满足G
中所有的边 都存在于这个环中一次, 那么这个环 称之为欧拉回路;
.
比如G: a<->b<->c
, 那么a->b->c->b->a
是一个欧拉回路;
#欧拉回路图#
存在欧拉回路的图, 称之为欧拉回路图;
.
结论: 有向图G, 如果{每个点的入度等于出度 | 所有边是连通的}, 那么G是欧拉回路图;
性质
算法
求欧拉回路路径
比如a->b->c->a, b->b
, 那么a->b->b->c->a
是一个欧拉回路, 你需要依次输出每条边的ID号;
做法是: 暴力DFS, 比如当前是dfs(a)
对于a->b
这个边 (令她的ID是X
), 我们先把这个边给删除掉 (即让FirstEdge[a] = NextEdge[ X]
), 然后dfs(b)
, 最后回溯时 再ANS.push_back(X)
; DFS结束后 reverse(ANS)
一下;
拿上面例子来说, 比如dfs次序: a1, b1, c, a2, b2
, 在c
这里回溯时 我们将c->a
放入答案, 然后在b1
回溯时 放入了b->c
, 然后在b1
回溯了b->b
, 最后在a1
回溯了a->b
;
auto Dfs = [&]( auto & _dfs, int _cur)->void{
for( ;_graph.FirstEdge[ _cur] != -1; ){
auto edgeID = _graph.FirstEdge[ _cur];
auto nex = _graph.DirectedEdges.at( edgeID).EndPoint;
_graph.FirstEdge[ _cur] = _graph.NextEdge[ edgeID];
_dfs( _dfs, nex);
ANS.push_back( edgeID + 1);
}
};
for( int i = 0; i < _graph.PointsCount; ++i){
if( _graph.FirstEdge[ i] != -1){
Dfs( Dfs, i); break;
}
}
std::reverse( ANS.begin(), ANS.end());
例题
@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=130304774
;
证明给定图是欧拉回路图;
欧拉回路(无向图)
定义
#欧拉回路#
给定无向图G, 如果存在一个环x->...->x
满足G
中所有的边 都存在于这个环中一次, 那么这个环 称之为欧拉回路;
.
比如G: a-b-c-a
, 那么a-b-c-a (或b-c-a-b 或c-a-b-c)
是一个欧拉回路;
#欧拉回路图#
存在欧拉回路的图, 称之为欧拉回路图;
.
结论: 无向图G, 如果{每个点的度数都是偶数 | 所有边是连通的}, 那么G是欧拉回路图;
算法
求欧拉回路路径
和有向图求欧拉回路差不多, 只不过 由于是无向边(即a-b
边 在代码层面 是由a<->b
两条边组成的), 因此 当我们遍历了a->b
(她要放到答案里) 那么同时要把她对应的b->a
给Vis=1
掉;
std::vector< bool> Vis( _graph.EdgesCount << 1, 0);
auto Dfs = [&]( auto & _dfs, int _cur)->void{
for( ;_graph.FirstEdge[ _cur] != -1; ){
auto edgeID = _graph.FirstEdge[ _cur];
auto nex = _graph.DirectedEdges.at( edgeID).EndPoint;
_graph.FirstEdge[ _cur] = _graph.NextEdge[ edgeID];
if( Vis[edgeID] == 0){
Vis[edgeID] = Vis[edgeID^1] = 1;
_dfs( _dfs, nex);
ANS.push_back( edgeID);
}
}
};
for( int i = 0; i < _graph.PointsCount; ++i){
if( _graph.FirstEdge[ i] != -1){
Dfs( Dfs, i); break;
}
}
std::reverse( ANS.begin(), ANS.end());
术语
有向图
Given a Directed-Graph G = ( V , E ) G =(V, E) G=(V,E)
An Semi-Eulerian-Path (半欧拉路径) is a path (i.e., a sequence of edges satisfying any two consecutive-edges share a same point) such that the start-point and end-point of the path are distinct, and every edge
e
∈
E
e \in E
e∈E occurs in the path exactly once;
+
The path would be the form
s
→
.
.
.
→
t
s
≠
t
s \to ... \to t \ \ s\neq t
s→...→t s=t, from the start-point
s
s
s, you can traverse the graph with passing though every edge exactly once, and finally arrived at
t
t
t.
+
The edges set of a Semi-Eulerian-Path equals to
E
E
E;
+
The path focuses on the edges, not points (i.e., it would not pass though a Isolated-Point which has no adjacent-edges; a point maybe passed multiple times);
G G G is called Semi-Eulerian (半欧拉图) if it has an Semi-Eulerian-Path;
--
An Eulerian-Circuit (欧拉回路) is an Semi-Eulerian-Path in which the restriction
s
≠
t
s \neq t
s=t replaced by
s
=
t
s = t
s=t.
+
The path would be the form
s
→
.
.
.
→
s
s \to ... \to s
s→...→s, from the start-point
s
s
s, you can traverse the graph with passing though every edge exactly once, and finally arrived at
s
s
s.
G G G is called Eulerian (欧拉图) if it has an Eulerian-Circuit;
--
An Eulerian-Path (欧拉路径) is either an Semi-Eulerian-Path or an Eulerian-Circuit.
无向图
Given a Undirected-Graph G = ( V , E ) G =(V, E) G=(V,E)
An Semi-Eulerian-Path (半欧拉路径) is a path (i.e., a sequence of edges satisfying any two consecutive-edges share a same point;) such that the start-point and end-point of the path are distinct, and every edge
e
∈
E
e \in E
e∈E occurs in the path exactly once;
+
The path would be the form
s
−
.
.
.
−
t
s
≠
t
s - ... - t \ \ s\neq t
s−...−t s=t, from the start-point
s
s
s, you can traverse the graph with passing though every edge exactly once, and finally arrived at
t
t
t.
.
Note that an edge in a Undirected-Path, in fact it is Directed; e.g.,
a
−
b
a-b
a−b in the path denotes from
a
a
a to
b
b
b; although an Undirected-Edge
a
−
b
a-b
a−b has two possible directions (
a
→
b
a\to b
a→b or
b
→
a
b\to a
b→a), but the direction of any edge
a
−
b
a-b
a−b is unique in a path.
+
The edges set of a Semi-Eulerian-Path equals to
E
E
E;
+
The path focuses on the edges, not points (i.e., it would not pass though a Isolated-Point which has no adjacent-edges; a point maybe passed multiple times);
G G G is called Semi-Eulerian (半欧拉图) if it has an Semi-Eulerian-Path;
--
An Eulerian-Circuit (欧拉回路) is an Semi-Eulerian-Path in which the restriction
s
≠
t
s \neq t
s=t replaced by
s
=
t
s = t
s=t.
+
The path would be the form
s
→
.
.
.
→
s
s \to ... \to s
s→...→s, from the start-point
s
s
s, you can traverse the graph with passing though every edge exactly once, and finally arrived at
s
s
s.
G G G is called Eulerian (欧拉图) if it has an Eulerian-Circuit;
--
An Eulerian-Path (欧拉路径) is either an Semi-Eulerian-Path or an Eulerian-Circuit.
半欧拉路径
有向图
Proposition-A: G G G has a Semi-Eulerian-Path (i.e., G G G is Semi-Eulerian-Graph)
Proposition-B:
1
There is one and only one start-point
s
s
s satisfying
O
u
t
[
s
]
−
I
n
[
s
]
=
1
Out[s] - In[s] = 1
Out[s]−In[s]=1; and,
2
There is one and only one end-point
t
t
t satisfying
I
n
[
t
]
−
O
u
t
[
t
]
=
1
In[t] - Out[t] = 1
In[t]−Out[t]=1; and,
3
I
n
[
x
]
=
O
u
t
[
x
]
∀
x
∈
V
/
{
s
,
t
}
In[x] = Out[x] \quad \forall x \in V/\{s,t\}
In[x]=Out[x]∀x∈V/{s,t}; and,
4
s
s
s can reach to all Non-Isolated-Points (
a
a
a is Isolated-Point if and only if
I
n
[
x
]
=
O
u
t
[
x
]
=
0
In[x]=Out[x] = 0
In[x]=Out[x]=0);
Conclusion: A = B A = B A=B
Proof:
A → B A \to B A→B: From the definition of a Semi-Eulerian-Path, it is obviously proved;
B → A B \to A B→A: Link
算法
path = a Semi-Eulerian-Path of the Graph;
void Dfs( int a){
for( `a->b` : all adjacent-edges of `a`){
auto cur_edge = `a->b`; //< a copy
delete this edge `a->b` from `G`;
Dfs( b);
ASSERT( `b` is Isolated (i.e., `b` has no adjacent-edges));
path.push_back( cur_edge);
}
}
Dfs( s);
inverse( path);
Annotation:
Firstly, we get a Limited-Path of
s
s
s, denoted
P
P
P, suppose that it is
s
→
.
.
.
→
t
s \to ... \to t
s→...→t, let
P
P
P be the sequence of all the points it passed by (i.e.,
S
=
[
s
,
.
.
.
,
t
]
S = [s,...,t]
S=[s,...,t]);
+
S
S
S may contain multiple identical points (e.g.,
s
,
t
,
s
,
t
,
a
,
t
s,t,s,t,a,t
s,t,s,t,a,t); a Non-Isolated-Point may not occurs in the path (e.g., the Semi-Eulerian-Graph
(
s
→
t
)
(
s
→
a
)
(
a
→
s
)
(s\to t) (s\to a) (a\to s)
(s→t)(s→a)(a→s), where
s
→
t
s\to t
s→t is a Limited-Path);
Secondly, note that, the current G G G has been changed, all edges of P P P has been removed from G G G;
set<> new_isolated;
for( `a` : $(the reversed `S`)){ //< `a = [t,...,s]`
p = the Limited-Path of `a` in `G`;
ASSERT( `p` is the form `[a,...,a]`); //< `p = [a]` is also valid
if( `p` in `new_isolated`){
ASSERT( `p` has no edge);
}
ASSERT( all points in `p` except `a`, would not occurs in `new_isolated`);
$(Remove all edges in `p` from `G`);
for( `b` : all points in `p`){
new_isolated.insert( b);
}
}
ASSERT( $(all Non-Isolated-Points in the Original `G`) would equals to `new_isolated`); //< also means `no $(Isolated-Points in the Original `G`) would occurs in `new_isolated`);
We call p
is a Loop if p
contains edges;
.
t
would not has Loop, cuz it is already Isolated after the First-Step;
The Limited-Path `P` of `s,t`
s, s, t, t, a, c, d, b, a, d, b, c, b, t, d, t, t, t
| |
Sc Sd
Sd = (d, b, s, b, s, d, b, d) //< must no `t`
Sc = (c, a, a, c, a, c) //< must no `t,d,b,s`
ASSERT( all others points except `c,d`, has no loop); //< note that, the above two `c,c` are distinct points in this context, cuz a point denotes a `Dfs(x)`, two same points can denotes different Dfs;
For the above illustration, we found a Eulerian-Path s,s,...,d,b, (Sc), b,t, (Sd), t,t,t
, so our goal is to get it.
But the DFS-sequence is
P
,
S
d
,
S
c
P, Sd, Sc
P,Sd,Sc which is not a Eulerian-Path; so, the algorithm is a bit of sophistication, it used a Property:
Once the DFS is back-tracking, that is:
Dfs( int a){
for( `a->b` : all adjacent-edges of `a`){
auto cur_edge = `a->b`; //< a copy
delete this edge `a->b` from `G`;
Dfs( b);
//>< @Loc_0
path.push_back( cur_edge);
}
}
When we at @Loc_0 (i.e., Dfs(b)
is finished), currently
b
b
b must be Isolated; cuz once DFS is back-tracking, it means it has found a Limited-Path, whatever it occurs in
P
P
P or
S
d
,
S
c
Sd, Sc
Sd,Sc;
Proof:
1
if a -> b
(i.e., Dfs(a) -> Dfs(b)
) is in
P
P
P, from above we know that b
must in new_isolated
;
2
if a -> b
(i.e., Dfs(a) -> Dfs(b)
) is in a Loop (e.g.,
S
d
Sd
Sd), once the DFS is finished (i.e., the whole Limited-Path has been deleted), all points in the Loop must in new_isolated
;
So, we perform path.push_back( cur_edge);
at @Loc_0, we would get t,t,t, (~Sd), t, b, (~Sc), b, d, ..., s, s
whose reverse is the answer (Eulerian-Path);
性质
+
The Eulerian-Path (either Semi-, or Circuit) itself is also a Limited-Path;
例题
无向图
Proposition-A: G G G has a Semi-Eulerian-Path (i.e., G G G is Semi-Eulerian-Graph)
Proposition-B:
1
There is two and only two points
s
,
t
s,t
s,t satisfying
D
e
g
[
s
]
=
D
e
g
[
t
]
=
O
d
d
Deg[s] = Deg[t] = Odd
Deg[s]=Deg[t]=Odd; and,
2
D
e
g
[
x
]
=
E
v
e
n
∀
x
∈
V
/
{
s
,
t
}
Deg[x] = Even \quad \forall x \in V/\{s,t\}
Deg[x]=Even∀x∈V/{s,t}; and,
3
s
s
s can reach to all Non-Isolated-Points (
a
a
a is Isolated-Point if and only if
D
e
g
[
x
]
=
0
Deg[x] = 0
Deg[x]=0);
Conclusion: A = B A = B A=B
Proof:
A → B A \to B A→B: From the definition of a Semi-Eulerian-Path, it is obviously proved;
B → A B \to A B→A: Link
性质
+
A Semi-Eulerian-Path
s
−
.
.
.
−
t
s - ... - t
s−...−t, its Converse-Path (i.e., an edge
a
−
b
a-b
a−b in the previous-path, becomes
b
−
a
b-a
b−a)
t
−
.
.
.
−
s
t-...-s
t−...−s is also a Semi-Eulerian-Path.
例题
算法
+
Similar to the Algorithm above for the Directed-Graph;
+
Link-The-Technique-for-Deleting-Edges;
欧拉回路
有向图
Proposition-A: G G G has a Eulerian-Circuit (i.e., G G G is Eulerian-Graph)
Proposition-B:
1
I
n
[
x
]
=
O
u
t
[
x
]
∀
x
∈
V
In[x] = Out[x] \quad \forall x \in V
In[x]=Out[x]∀x∈V; and,
2
Let
x
x
x be a Non-Isolated-Points, then
x
x
x can reach to all Non-Isolated-Points (
a
a
a is Isolated-Point if and only if
I
n
[
x
]
=
O
u
t
[
x
]
=
0
In[x]=Out[x] = 0
In[x]=Out[x]=0);
Conclusion: A = B A = B A=B
Proof:
A → B A \to B A→B: From the definition of a Semi-Eulerian-Path, it is obviously proved;
B → A B \to A B→A: Link
性质
+
Eulerian-Graph is the SCC of itself;
例题
算法
Similar to the Algorithm-for-Semi-Eulerian-Path;
无向图
Proposition-A: G G G has a Eulerian-Circuit (i.e., G G G is Eulerian-Graph)
Proposition-B:
1
D
e
g
[
x
]
=
E
v
e
n
∀
x
∈
V
Deg[x] = Even \quad \forall x \in V
Deg[x]=Even∀x∈V; and,
2
Let
x
x
x be a Non-Isolated-Points, then
x
x
x can reach to all Non-Isolated-Points (
a
a
a is Isolated-Point if and only if
D
e
g
[
x
]
=
0
Deg[x] = 0
Deg[x]=0);
Conclusion: A = B A = B A=B
Proof:
A → B A \to B A→B: From the definition of a Semi-Eulerian-Path, it is obviously proved;
B → A B \to A B→A: Link
算法
Similar to the Algorithm-for-Semi-Eulerian-Path;
例题
证明
半欧拉路径-有向图
--
A Directed-Graph
G
=
(
V
,
E
)
G = (V,E)
G=(V,E) satisfying:
1
There is one and only one start-point
s
s
s satisfying
O
u
t
[
s
]
−
I
n
[
s
]
=
1
Out[s] - In[s] = 1
Out[s]−In[s]=1; and,
2
There is one and only one end-point
t
t
t satisfying
I
n
[
t
]
−
O
u
t
[
t
]
=
1
In[t] - Out[t] = 1
In[t]−Out[t]=1; and,
3
I
n
[
x
]
=
O
u
t
[
x
]
∀
x
∈
V
/
{
s
,
t
}
In[x] = Out[x] \quad \forall x \in V/\{s,t\}
In[x]=Out[x]∀x∈V/{s,t};
Conclusion: The end-point of the Limited-Path of s s s must be t t t;
Proof:
+
For the point
s
s
s: Initially,
O
u
t
[
s
]
=
I
n
[
s
]
+
1
Out[s]=In[s]+1
Out[s]=In[s]+1 when we at
s
s
s, once we leave it, it becomes
O
u
t
[
s
]
=
I
n
[
s
]
Out[s] = In[s]
Out[s]=In[s];
.
Then, once we arrived at
s
s
s, now
O
u
t
[
s
]
=
I
n
[
s
]
−
1
Out[s] = In[s] - 1
Out[s]=In[s]−1, it means
I
n
[
s
]
≥
1
In[s] \geq 1
In[s]≥1, so it must traverse further to the next-point;
.
As a result,
s
s
s would not be the end-point of the Limited-Path of
s
s
s;
+
For these points
x
∈
V
/
{
s
,
t
}
x \in V/ \{s,t\}
x∈V/{s,t}: Initially,
O
u
t
[
x
]
=
I
n
[
x
]
Out[x]=In[x]
Out[x]=In[x];
.
Then, once we arrived at
x
x
x, now
O
u
t
[
x
]
=
I
n
[
x
]
−
1
Out[x] = In[x] - 1
Out[x]=In[x]−1, it means
I
n
[
s
]
≥
1
In[s] \geq 1
In[s]≥1, so it must traverse further to the next-point;
.
As a result,
x
x
x would not be the end-point of the Limited-Path of
s
s
s;
--
Let P P P be a Limited-Path s → . . . → t s \to ... \to t s→...→t, and G 1 = ( V , E 1 ) G1 = (V,E1) G1=(V,E1) where E 1 = E − P E1 = E - P E1=E−P denoted all edges of P P P has been deleted from E E E.
Conclusion: Iterating all points p ∈ P p \in P p∈P, find the Limited-Path of p p p in G 1 G1 G1, p → . . . → p 1 p \to ... \to p1 p→...→p1 where p p p would equals p 1 p1 p1, then deletes there edge from G 1 G1 G1, finally, G 1 G1 G1 would has no edges;
Proof-1:
p
=
p
1
p = p1
p=p1;
+
Cuz
G
1
G1
G1 satisfying
I
n
[
x
]
=
O
u
t
[
x
]
∀
x
In[x] = Out[x] \quad \forall x
In[x]=Out[x]∀x, the Limited-Path of any point
a
a
a must be the form
a
→
.
.
.
→
a
a \to ... \to a
a→...→a;
Proof-2:
G
1
G1
G1 would no edges finally;
+
Disproof: if there is edge
a
→
b
a\to b
a→b not be deleted, that shows
∀
v
∈
P
\forall v \in P
∀v∈P cannot reach to
a
a
a, then
s
s
s cannot reach to
a
a
a; this contradicts the assumption
s
s
s can reach to all Non-Isolated-Points;
----
半欧拉路径-无向图
欧拉回路-有向图
Similar to Link
欧拉回路-无向图
----
Redirected-Id: 4