Upload
davida
View
58
Download
0
Embed Size (px)
DESCRIPTION
101 北一女中 資訊選手培訓營. 深度優先搜尋 (DFS) 與 廣度優先搜尋 (BFS). 2012.07.08 Nan. 學了圖論基礎後 ….what’s next?. 走訪 - Traversal. 給你一張圖,把所有的節點走過一次的方法,我們稱為圖的走訪 (Graph Traversal) 走訪可以有任意順序,但是特定的順序會產生特定的性質。 最常用的走訪有兩種: 深度優先搜尋 (Depth First Search, DFS) 廣度優先搜尋 (Breath First Search, BFS). 1. 3. 5. 2. 6. 4. - PowerPoint PPT Presentation
Citation preview
101 北一女中資訊選手培訓營深度優先搜尋 (DFS)
與廣度優先搜尋 (BFS)2012.07.08 Nan
學了圖論基礎後… .what’s next?
走訪 - Traversal
• 給你一張圖,把所有的節點走過一次的方法,我們稱為圖的走訪 (Graph Traversal)
• 走訪可以有任意順序,但是特定的順序會產生特定的性質。
• 最常用的走訪有兩種:深度優先搜尋 (Depth First Search, DFS)廣度優先搜尋 (Breath First Search, BFS)
舉個例子來說
11 33
22
44
66
55
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
1
堆疊 Stack
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
1
2
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
4
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
6D = 2
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
6D = 2
D = 3
3
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
6D = 2
D = 3
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
6D = 2
D = 3
D = 3
5
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
6D = 2
D = 3
D = 3
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
2
D = 2
D = 3
D = 3
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
1
D = 2
D = 3
D = 3
深度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2 D = 2
D = 3
D = 3
走訪順序: 1 2 4 6 3 5
實作• 通常都用遞迴來實作• 你剛剛看到的堆疊會因此隱藏起來 ( 遞迴會
有系統的堆疊 )• 習慣上會把 map 、 visited( 紀錄有沒有被
走過的、以及其他相關資訊放到 global 變數,讓遞迴能夠存取。
int N = # node;int map[N+1][N+1] = {{…},{…},…};int visited[N+1] = {0};int depth[N+1];
void dfs(int id){ int i; printf(“%d\n”, id); for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i); } } }
int main(){ visited[1] = 1; depth[1] = 0; dfs(1);}
11 33
22
44
66
55
D = 0
1
堆疊
visited[1] = 1; depth[1] = 0; dfs(1);
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
dfs(2)
11 33
22
44
66
55
D = 0
D = 1
1
2
dfs(2)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
dfs(4)
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
4
dfs(4)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
結束 !return! 會回到 dfs(2) 時的 for 迴圈繼續跑
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
return 回到dfs(4)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
dfs(6)
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
6D = 2
dfs(6)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
dfs(3)
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
6D = 2
D = 3
3
dfs(3)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
結束 !return! 會回到 dfs(6) 時的 for 迴圈繼續跑
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
6D = 2
D = 3
return 回到dfs(6)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
dfs(5)
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
6D = 2
D = 3
D = 3
5
dfs(5)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
結束 !return! 會回到 dfs(6) 時的 for 迴圈繼續跑
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
6D = 2
D = 3
D = 3
return 回到dfs(6)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
結束 !return! 會回到 dfs(2) 時的 for 迴圈繼續跑
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
2
D = 2
D = 3
D = 3
return 回到dfs(2)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
結束 !return! 會回到 dfs(1) 時的 for 迴圈繼續跑
11 33
22
44
66
55
D = 0
D = 1
D = 2
1
D = 2
D = 3
D = 3
return 回到dfs(1)
void dfs(int id){ int i; for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; depth[i] = depth[id] + 1; dfs(i);
結束 !return! 會回到 main 去 結束 !
11 33
22
44
66
55
D = 0
D = 1
D = 2 D = 2
D = 3
D = 3
print 出來的: 1 2 4 6 3 5
return 回到main 裡的 dfs(1) 後,等於完成 ~
你可能有聽過所謂的“暴搜”• DFS 的變化型,本來是只找一種走法把圖
走過,變成試過所有走法• 關鍵點在於 : 自己的鄰居都走完 return 回
來後,把自己設回沒有走過。• 或者反過來說是每個鄰居下去走過以後,
設回沒走過• 通常需要一個暫存的陣列放置目前走訪的
順序,走到底再一次印出
int N = # node;int map[N+1][N+1] = {{…},{…},…};int visited[N+1] = {0};int path[N+1];
void dfs(int id, int depth){ int i; if ( depth >= N ){ for ( i = 0 ; i < N ; i++ ) printf(“ %d”, path[i]); putchar(‘\n’); return; } for ( i = 1 ; i <= N ; i++ ){ if ( map[id][i] == 1 && visited[i] == 0 ) { visited[i] = 1; path[depth] = i; dfs(i, depth + 1); visited[i] = 0; // 還原 ! } } }
int main(){ visited[1] = 1; path[0] = 1; dfs(1, 1);}
廣度優先搜尋
11 33
22
44
66
55
D: 深度
1
D = 0
佇列 (Queue)
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
1 2 3
D = 1
D = 1
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
2 3
D = 1
D = 1
咖啡色:已經走過橘色:目前所在位置皮膚色:已在 queue 中粉紅色:此次加入 queue
4 6
D = 2D = 2
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
3
D = 1
D = 2
咖啡色:已經走過橘色:目前所在位置皮膚色:已在 queue 中粉紅色:此次加入 queue
4 6
D = 2D = 2
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
咖啡色:已經走過橘色:目前所在位置皮膚色:已在 queue 中粉紅色:此次加入 queue
4 6
D = 2D = 2
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
咖啡色:已經走過橘色:目前所在位置皮膚色:已在 queue 中粉紅色:此次加入 queue
6
D = 2D = 2
5
D = 3
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
咖啡色:已經走過橘色:目前所在位置皮膚色:已在 queue 中粉紅色:此次加入 queue
D = 2D = 2
5
D = 3
廣度優先搜尋
11 33
22
44
66
55
D = 0
D: 深度
D = 1
D = 2
D = 2D = 2
D = 3
走訪順序: 1 2 3 4 6 5
實做 ( 通常直接在 main 裡 )int N = # nodes;int q[N * N + 1];int map[N+1][N+1] = {{…},{…},…};int visited[N+1] = {0};int head, tail = 0;int i;q[0] = 1;visited[1] = 1;
for(head=0; head<tail; head++){
for(i=1; i<=N; i++){
if(visited[i] == 0 && map[q[head]][i] == 1) {
q[tail] = i; tail++;
}}
}
實做 ( 棋盤式地圖 )int way_x[4] = {1, -1, 1, -1};int way_y[4] = {1, 1, -1, -1};for(head=0; head<tail; head++){
for(i=0; i<4; i++) { if(map[qx[head] + way_x[i]][qy[head] + way_y[i]]) {
map[qx[head] + way_x[i]][qy[head] + way_y[i]] = 1;
qx[tail] = qx[head] + way_x[i];qy[tail] = qy[head] + way_y[i];qn[tail] = qn[head] + 1;tail++;
} }
}
BFS 的特性• 將同一層的所有節點走完,才會走向下一層• 走出來的會是最短路徑 ( 假設邊的 weight = 1)• 用 Queue 來輔助• 時間複雜度 O(V + E)
DFS vs. BFS
11 33
22
44
66
55
11 33
22
44
66
55
DFS vs. BFS
11
3322
44 66
55
11
33
22
44 66
55