您當前的位置:首頁 > 書法

判斷圖的連通性的三種方法:DFS、BFS 和並查集

作者:由 賈恆 發表于 書法時間:2020-08-27

1 什麼是結點的連通性?

若圖 G 中兩個不同的結點 u 和 v 存在路徑 e,則稱結點 u 和結點 v 連通。

2 什麼是圖的連通性?

若圖 G 中任意兩個結點連通,則稱圖 G 連通。

判斷圖的連通性的三種方法:DFS、BFS 和並查集

3 怎樣判斷圖的連通性?

判斷圖的連通性的常見方法有三種:DFS、BFS 和並查集。

3。1 DFS

深度優先遍歷得到的是圖的一個連通分量。

演算法流程:

從某個結點 v 出發,訪問結點 v,並令

vis[v] = 1

查詢 v 的所有鄰接點 i,若結點 i 並未被訪問過(

vis[i] = 0

),則從結點 i 出發,深度優先遍歷圖,轉至步驟(1)。

遞迴結束後,遍歷 vis 陣列,若陣列中有一個值不為 1,則說明該點未被訪問,圖不連通。

3。2 BFS

演算法流程:

從某個結點 v 出發,將結點 v 放入佇列 q 中;

佇列不空時,彈出隊首結點 v;

如果結點 v 沒被訪問過,查詢 v 的所有鄰接點 i;

如果結點 i 沒被訪問過,放入佇列 q 中;

如果結點 i 已被訪問,跳過。

如果結點 v 已被訪問,跳過。

標記結點 v 已被訪問(

容易遺漏!!!

)。

佇列為空時,遍歷 vis 陣列,若陣列中有一個值不為 1,則說明該點未被訪問,圖不連通。

3。3 並查集

並查集可以簡單理解為找根結點,使用 father 陣列記錄每個結點的根節點。

演算法流程:

初始化每個結點的根節點為結點本身;(可使用

iota()

函式)

從某個結點 v 開始,查詢 v 的所有鄰接點 i,如果結點 v 和結點 i 的根節點不同(

father[v] != father[i]

),則把兩個結點的根節點設為下標較小的根節點(

father[v] = father[i] = min(father[v], father[i])

)。

迴圈結束時,遍歷 father 陣列,若陣列中有一個值不為 0,則說明該點的根節點並不是 0 號結點,圖不連通。

3。4 比較

DFS 和 BFS 都是記錄結點是否已訪問,而並查集是記錄每個結點的根節點。

三種演算法都需要查詢當前結點的所有鄰接點,因而建議以鄰接表的形式儲存圖。

三種演算法的時間複雜度和空間複雜度如下表所示,其中 E 為邊的數目,V 為結點的數目。

判斷圖的連通性的三種方法:DFS、BFS 和並查集

4 程式碼

判斷圖的連通性的三種方法:DFS、BFS 和並查集

#include

#include

#include

#include

using

namespace

std

vector

<

vector

<

int

>>

g

int

n

vector

<

int

>

vis

vector

<

int

>

father

void

dfs

int

v

{

cout

<<

v

<<

“ ”

vis

v

=

1

for

int

i

=

0

i

<

g

v

]。

size

();

i

++

{

if

vis

g

v

][

i

]])

{

dfs

g

v

][

i

]);

}

}

}

void

bfs

()

{

queue

<

int

>

q

q

push

0

);

while

q

empty

())

{

int

v

=

q

front

();

cout

<<

v

<<

“ ”

q

pop

();

if

vis

v

])

{

for

int

i

=

0

i

<

g

v

]。

size

();

i

++

{

if

vis

g

v

][

i

]])

{

q

push

g

v

][

i

]);

}

}

}

vis

v

=

1

}

}

int

Find

int

x

{

int

a

=

x

while

x

!=

father

x

])

{

x

=

father

x

];

}

while

a

!=

father

a

])

{

int

z

=

a

a

=

father

a

];

father

a

=

x

}

return

x

}

void

Union

int

a

int

b

{

int

fA

=

Find

a

);

int

fB

=

Find

b

);

father

a

=

father

b

=

min

fA

fB

);

}

int

main

()

{

n

=

6

g

=

vector

<

vector

<

int

>>

n

vector

<

int

>

());

// 插入 6 條邊(雙向)

g

0

]。

push_back

1

);

g

0

]。

push_back

2

);

g

0

]。

push_back

5

);

g

1

]。

push_back

0

);

g

2

]。

push_back

0

);

g

2

]。

push_back

3

);

g

3

]。

push_back

2

);

g

3

]。

push_back

4

);

g

3

]。

push_back

5

);

g

4

]。

push_back

3

);

g

5

]。

push_back

0

);

g

5

]。

push_back

3

);

// DFS

vis

=

vector

<

int

>

n

0

);

dfs

0

);

cout

<<

endl

//0 1 2 3 4 5

// BFS

vis

=

vector

<

int

>

n

0

);

bfs

();

cout

<<

endl

//0 1 2 5 3 3 4

// Union-Find Set

father

=

vector

<

int

>

n

);

iota

father

begin

(),

father

end

(),

0

);

for

int

i

=

0

i

<

n

i

++

{

for

int

j

=

0

j

<

g

i

]。

size

();

j

++

{

if

father

i

!=

father

g

i

][

j

]])

{

cout

<<

i

<<

“ ”

<<

g

i

][

j

<<

endl

Union

i

g

i

][

j

]);

}

}

}

//0 1

//0 2

//0 5

//2 3

//3 4

// 可透過求和判斷陣列內所有元素是否都為 0:

cout

<<

accumulate

father

begin

(),

father

end

(),

0

==

0

<<

endl

//1

return

0

}

References

無向圖連通性判斷的五種方法(BFS、DFS、Union-find、Warshell、Tarjan)

標簽: 結點  father  push  Back  vis