深度優先搜尋(DFS)與 廣度優先搜尋(BFS)

Slides:



Advertisements
Similar presentations
如何科学认识风水 主讲嘉宾孙百川 揭开神秘的面纱 揭开神秘的面纱 破除迷信的枷锁 破除迷信的枷锁 还易经本来面目 还易经本来面目 学易用易不迷易 学易用易不迷易.
Advertisements

魏晉南北朝的胡漢融和概況. 北朝的漢胡融和 1) 北朝漢胡 融和的概 況 2) 北魏孝文 帝推行的 漢化措施 及影響 北邊民族徙居中原,由 來已久。自曹魏招用胡 兵始,沿邊胡族內徙日 繁。不少胡族君主更傾 心嚮慕漢族文化,大力 促成胡漢的融和。北魏 推行的漢化措施,影響 尤為深遠。
大陸學歷採認相關問題 楊景堯 淡江大學中國大陸研究所. 學歷採認的定義與範圍 廣義的定義 — 承認學歷 狹義的定義 — 具備任職, 任教, 考試資格 範圍 — 高等教育為主 台灣人取得大陸學歷的採認 大陸人取得大陸學歷的採認 外國人取得大陸學歷的採認.
模仿貓 記敘文 ( 童話 ) 作者: 海倫、波頓 課文朗讀課文朗讀、模仿大賽 作者 美國女畫家,她用藝術家的嚴 肅態度和精神,幫兒童讀繪畫 插圖,並得過許多次獎。她的 作品藝術價值高,有雨本成為 美國美術協會兒童讀物展覽的 入選作品。她常常自寫自畫, 文筆很不錯。
如何做個稱職的父母 財團法人雲林縣雲萱婦幼文教基金會 王招萍.
國小學童財金生活教育 主講人: 秘書長陳琬惠 社團法人中華民國財金智慧教育推廣協會.
《少年小樹之歌》簡介: 凡是讀過這本書的人 一定永遠忘不了他們是在何年何月何地 還有為什麼買下它的 小樹的讀者們將永遠記得
   時間 國立臺南師範學院數學教育系     謝  堅.
程焕文 中山大学资讯管理学院 2015年10月17日 山东·临沂
第7章 樹與二元樹 (Trees and Binary Trees)
校园信息管理系统 河北科技大学网络中心 2000/4/10.
中國地名、組織機構名稱和英譯名的自動辨識
传媒产业的集团化经营和管理.
徵收苗栗市福全段147、1588及文心段10、11地號等4筆土地之
讲 义 大家好!根据局领导的指示,在局会计科和各业务科室的安排下,我给各位简要介绍支付中心的工作职能和集中支付的业务流程。这样使我们之间沟通更融洽,便于我们为预算单位提供更优质的服务。 下面我主要从三方面介绍集中支付业务,一是网上支付系统,二是集中支付业务流程及规定等,
中国人民公安大学经费管理办法(试行) 第一章总则 第四条:“一支笔” “一支笔”--仅指单位主要负责人。负责对本 单位的经费进行审核审批。
9理直氣和—記敘文 說理如強硬,則不易被接受,以故事方式來激發反思,是比較不傷和氣而且高明的技巧。
資料結構與C++程式設計進階 資料結構概論 講師:林業峻 CSIE, NTU 6/ 7, 2010.
Chap5 Graph.
Linked List Operations
單向鏈結串列 Singly Linked Lists.
Chap5 Graph.
4.4 佇列 特徵: c b a c b d c b 新增 d 刪除 入口 入口 入口 尾端(rear) 尾端(rear) 尾端(rear)
講師:郭育倫 第3章 基本資料結構 講師:郭育倫
第8章 圖形結構(Graphs) 8-1 圖形的基本觀念 8-2 圖形的表示法 8-3 圖形的走訪 8-4 擴張樹
补充内容 结构体 概述 定义结构体类型和定义结构体变量 结构体变量的引用 结构体变量的初始化 指针与结构体 用typedef定义类型的别名.
Chapter 6 Graph Chang Chi-Chung
101北一女中 資訊選手培訓營 快速排序函式qsort() Nan.
第八章 图 图的基本概念 图的存储结构 图的遍历与连通性 最小生成树 最短路径 活动网络.
101北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
第十五章 Linked List, Stack and Queue
Function.
101北一女中 資訊選手培訓營 圖論基礎 Nan.
Solving problems by searching 利用搜尋法解決問題
(Circular Linked Lists)
Chapter 7 圖形與網路 資料結構導論 - C語言實作.
第3章 堆栈和队列 堆栈 堆栈应用 队列 队列应用 优先级队列 主要知识点.
資料結構與C++程式設計進階 堆疊與佇列(Stack & Queue) 講師:林業峻 CSIE, NTU 6/ 21, 2010.
計數式重複敘述 for 迴圈 P
Ch07 圖形與網路 淡江大學 周清江
二叉树的遍历.
資料結構 優點 缺點 1 陣列 (Array) 沒有額外變量 (例head, next,...) 運作/操作較簡單 更新資料時,若要保持順序,需要移動較大量資料 靜態結構Static (宣告時已決定了陣列元素多少,不能在程式執行期間增減元素) 2 隊列Queue (FIFO) 容易更新 加入enqueue:
辅导课程八.
第五章 递归与广义表 递归的概念 递归过程与递归工作栈 递归与回溯 广义表.
今天, AC 你 了吗? 2019/4/26.
第7章 樹與二元樹(Trees and Binary Trees)
101北一女中 資訊選手培訓營 深度優先搜尋(DFS)的進階應用 Nan.
最大網路流 Max (Network) Flow
Teacher: 郭育倫 Mail: 演算法 Teacher: 郭育倫 Mail:
微信商城系统操作说明 色卡会智能门店.
103資訊學科培訓 圖論 - BFS & DFS & 應用 講者:林庭宇.
資料結構與C++程式設計進階 遞迴(Recursion) 講師:林業峻 CSIE, NTU 6/ 17, 2010.
北一女中 資訊選手培訓營 圖論基礎 By Nan( ).
第8章 图 8.1 图的基本概念和基本操作 8.2 图的邻接矩阵存储结构 8.3 图的邻接表存储结构 8.4 图的其他存储结构
Course 8 回溯、分枝與限制 Backtracking, Branch-and-Bound
图(二).
鄧姚文 資料結構 第八章:圖(Graph) 鄧姚文
進階資料結構(2) Disjoint Sets
12797: Letters ★★★☆☆ 題組:Problem Set Archive with Online Judge
北一女中 資訊選手培訓營 妳不可不了解的指標 Nan.
大綱 一.受試者之禮券/禮品所得稅規範 二.範例介紹 三.自主管理 四.財務室提醒.
All Sources Shortest Path The Floyd-Warshall Algorithm
Advanced Competitive Programming
Advanced Competitive Programming
圖形結構 Graph Structure chapter 9 德明科技大學資訊科技系.
第7章 图.
最大網路流 Max (Network) Flow
题目详细要求、参考资料及更新发布于: 第二周 链表与指针 题目详细要求、参考资料及更新发布于:
資料結構與C++程式設計進階 C++與資料結構 講師:林業峻 CSIE, NTU 7/ 5, 2010.
JAVA 程式設計與資料結構 第二十一章 Graph.
Presentation transcript:

深度優先搜尋(DFS)與 廣度優先搜尋(BFS) 101北一女中 資訊選手培訓營 深度優先搜尋(DFS)與 廣度優先搜尋(BFS) 2012.07.08 Nan

學了圖論基礎後….what’s next?

走訪 - Traversal 給你一張圖,把所有的節點走過一次的方法,我們稱為圖的走訪 (Graph Traversal) 走訪可以有任意順序,但是特定的順序會產生特定的性質。 最常用的走訪有兩種: 深度優先搜尋 (Depth First Search, DFS) 廣度優先搜尋 (Breath First Search, BFS)

舉個例子來說 1 3 2 4 6 5

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 0 1 堆疊 Stack

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 0 D = 1 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 0 D = 1 4 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 0 D = 1 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 0 D = 1 6 D = 2 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 3 D = 0 D = 1 3 6 D = 2 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 3 D = 0 D = 1 6 D = 2 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 3 D = 0 D = 1 D = 3 5 6 D = 2 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 3 D = 0 D = 1 D = 3 6 D = 2 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 3 D = 0 D = 1 D = 3 D = 2 D = 2 2 1

深度優先搜尋 D: 深度 1 3 2 4 6 5 D = 3 D = 0 D = 1 D = 3 D = 2 D = 2 1

深度優先搜尋 D: 深度 走訪順序:1 2 4 6 3 5 1 3 D = 3 D = 0 5 2 D = 1 D = 3 6 D = 2

實作 通常都用遞迴來實作 你剛剛看到的堆疊會因此隱藏起來(遞迴會有系統的堆疊) 習慣上會把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);

堆疊 visited[1] = 1; depth[1] = 0; dfs(1); 1 3 dfs(2) D = 0 5 2 6 4 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); visited[1] = 1; depth[1] = 0; dfs(1); 1 3 2 4 6 5 dfs(2) D = 0 1 堆疊

dfs(2) 1 dfs(4) 3 D = 0 5 2 D = 1 6 4 2 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) 1 3 2 4 6 5 dfs(4) D = 0 D = 1 2 1

dfs(4) 1 結束!return! 3 會回到dfs(2)時的for迴圈繼續跑 D = 0 5 2 D = 1 6 4 D = 2 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(4) 1 3 2 4 6 5 結束!return! 會回到dfs(2)時的for迴圈繼續跑 D = 0 D = 1 4 D = 2 2 1

return回到 dfs(4) 1 dfs(6) 3 D = 0 5 2 D = 1 6 D = 2 4 2 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回到 dfs(4) 1 3 2 4 6 5 dfs(6) D = 0 D = 1 D = 2 2 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(6) 1 3 2 4 6 5 dfs(3) D = 0 D = 1 6 D = 2 D = 2 2 1

dfs(3) 1 結束!return! 3 D = 3 會回到dfs(6)時的for迴圈繼續跑 D = 0 5 2 D = 1 6 3 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) 1 3 2 4 6 5 結束!return! 會回到dfs(6)時的for迴圈繼續跑 D = 3 D = 0 D = 1 3 6 D = 2 D = 2 2 1

return回到 dfs(6) 1 dfs(5) 3 D = 3 D = 0 5 2 D = 1 6 6 D = 2 D = 2 4 2 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回到 dfs(6) 1 3 2 4 6 5 dfs(5) D = 3 D = 0 D = 1 6 D = 2 D = 2 2 1

dfs(5) 1 結束!return! 3 D = 3 會回到dfs(6)時的for迴圈繼續跑 D = 0 5 2 D = 1 D = 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); dfs(5) 1 3 2 4 6 5 結束!return! 會回到dfs(6)時的for迴圈繼續跑 D = 3 D = 0 D = 1 D = 3 5 6 D = 2 D = 2 2 1

return回到 dfs(6) 1 結束!return! 3 D = 3 會回到dfs(2)時的for迴圈繼續跑 D = 0 5 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(6) 1 3 2 4 6 5 結束!return! 會回到dfs(2)時的for迴圈繼續跑 D = 3 D = 0 D = 1 D = 3 6 D = 2 D = 2 2 1

return回到 dfs(2) 1 結束!return! 3 D = 3 會回到dfs(1)時的for迴圈繼續跑 D = 0 5 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(2) 1 3 2 4 6 5 結束!return! 會回到dfs(1)時的for迴圈繼續跑 D = 3 D = 0 D = 1 D = 3 D = 2 D = 2 2 1

return回到 dfs(1) 1 結束!return! 3 D = 3 會回到main去 結束! D = 0 5 2 D = 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回到 dfs(1) 1 3 2 4 6 5 結束!return! 會回到main去 結束! D = 3 D = 0 D = 1 D = 3 D = 2 D = 2 1

return回到 main裡的dfs(1)後,等於完成~ 3 2 4 6 5 D = 3 D = 0 D = 1 D = 3 D = 2 D = 2 print出來的:1 2 4 6 3 5

你可能有聽過所謂的“暴搜” 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);

廣度優先搜尋 D: 深度 1 3 2 4 6 5 D = 0 1 佇列(Queue)

廣度優先搜尋 D: 深度 1 3 2 4 6 5 D = 1 D = 0 D = 1 1 2 3

廣度優先搜尋 D: 深度 咖啡色:已經走過 橘色:目前所在位置 皮膚色:已在queue中 粉紅色:此次加入queue 1 3 2 4 6 5

廣度優先搜尋 D: 深度 咖啡色:已經走過 橘色:目前所在位置 皮膚色:已在queue中 粉紅色:此次加入queue 1 3 2 4 6 5

廣度優先搜尋 D: 深度 咖啡色:已經走過 橘色:目前所在位置 皮膚色:已在queue中 粉紅色:此次加入queue 1 3 2 4 6 5

廣度優先搜尋 D: 深度 咖啡色:已經走過 橘色:目前所在位置 皮膚色:已在queue中 粉紅色:此次加入queue 1 3 2 4 6 5

廣度優先搜尋 D: 深度 咖啡色:已經走過 橘色:目前所在位置 皮膚色:已在queue中 粉紅色:此次加入queue 1 3 D = 2 4 6 5 D = 2 D = 0 D = 3 D = 1 咖啡色:已經走過 橘色:目前所在位置 皮膚色:已在queue中 粉紅色:此次加入queue D = 2 D = 2 5

廣度優先搜尋 D: 深度 走訪順序:1 2 3 4 6 5 1 3 D = 2 D = 0 D = 3 5 2 D = 1 6 D = 2

實做(通常直接在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 1 3 1 3 5 5 2 2 6 6 4 4

DFS vs. BFS 1 1 2 3 2 4 4 6 6 5 5 3