1. 程式人生 > 其它 >藍橋杯第三次培訓之圖的深度遍歷和廣度遍歷

藍橋杯第三次培訓之圖的深度遍歷和廣度遍歷

技術標籤:藍橋杯演算法dfs圖論

圖的遍歷
圖的遍歷是指從圖中某一個頂點出發訪遍圖中其餘頂點,且使每一個頂點僅被訪問一次
圖的遍歷演算法是求解圖的連通性問題、拓撲排序和求關鍵路徑等演算法的基礎
由於圖結構本身的複雜性,所以其遍歷也較複雜,主要體現在:
(1)圖中任意一個頂點可作為第一個被訪問的頂點
(2)如何選取不同連通分量上的訪問出發點
(3)圖中如果有迴路,可能重複訪問
(4)如何選取下一個要訪問的鄰接點
一個圖有那麼多個結點,
如何遍歷這些結點,需要特定策略,一般有兩種訪問策略:深度優先遍歷、廣度優先遍歷
圖的深度遍歷
深度優先遍歷,從初始訪問結點出發,我們知道初始訪問結點可能有多個鄰接結點,深度優先遍歷的策略就是首先訪問第一個鄰接結點,然後再以這個被訪問的鄰接結點作為初始結點,訪問它的第一個鄰接結點。總結起來可以這樣說:每次都在訪問完當前結點後首先訪問當前結點的第一個鄰接結點。

第一步:假設初始狀態是圖中所有頂點均未被訪問,則可以從圖中某個頂點出發,訪問此頂點。然後,依次從它的未被訪問的鄰接點出發深度優先遍歷圖,直至圖中所有和它有路徑相通的頂點均被訪問到

第二步:若此時圖中尚有未被訪問的頂點,則另選圖中一個未曾被訪問的頂點作起始點。重複上述過程,直至圖中所有頂點均被訪問過為止
注:為了防止頂點重複訪問,可為每個頂點設定一個訪問標誌,若等於true,則說明該頂點已被訪問,頂點不得重複訪問;等於false,則訪問該頂點
圖一
如上圖所示對其進行深度遍歷為:0,1,3,4,5,2
程式碼實現

#include <stdio.h>
#include <iostream>
#include <queue> #include <vector> #include <algorithm> using namespace std; const int maxn = 100; int a[maxn][maxn]={0};//兩點時間是否連線 bool ju[maxn]={false};//判斷是否遍歷成功 int n,m; void dfs(int x) { cout<<x<<' '; ju[x]=true; for(int i=0;i<n;i++) { if(ju[i]==false&&
a[x][i])//找出其鄰居點且未遍歷,進行遍歷 { dfs(i);//遍歷該點 } } } int main() { fill(a[0],a[0]+maxn*maxn,0);//初始化所有邊都沒有連線 fill(ju,ju+maxn,false);//初始化所有邊都未訪問 scanf("%d %d",&n,&m); for(int i=0;i<m;i++) { int x,y;//輸入連線的兩個點 scanf("%d %d",&x,&y); a[x][y]=1; } for(int i=0;i<n;i++) { if(ju[i]==false)//該點是否遍歷過 { dfs(i);//遍歷該點 } } return 0; }

總結:深度搜索是一種列舉所有可能以遍歷所有情況的搜尋方法
練習題目:
習題一:http://codeup.cn/problem.php?cid=100000608&pid=0
習題二:http://codeup.cn/problem.php?cid=100000608&pid=1
圖的廣度搜索
廣度遍歷或廣度優先搜尋(BFS):類似樹的層序遍歷,也需要佇列配合
第一步:假設初始狀態是圖中所有頂點均未被訪問,則可以從圖中某個頂點出發,訪問此頂點。然後,依次遍歷它的未曾遍歷過的所有鄰接點,並使“先被訪問的頂點的鄰接點” 先於 “後被訪問的頂點的鄰接點” 被訪問,直至圖中所有已被訪問的頂點的鄰接點均被訪問到

第二步:若此時圖中尚有未被訪問的頂點,則另選圖中一個未曾被訪問的頂點作起始點。重複上述過程,直至圖中所有頂點均被訪問過為止

注:為了防止頂點重複訪問,與深度遍歷一樣需要為每個頂點設定一個訪問標誌
在這裡插入圖片描述
廣度搜索:0,1,2,3,4,5
程式碼實現

#include <stdio.h>
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
const int maxn = 100;
int a[maxn][maxn]={0};
bool ju[maxn]={false};
int n,m;
queue <int> q;
void bfs()
{
	while(!q.empty())
	{
		int x=q.front();
		q.pop();
		cout<<x<<' ';
		for(int i=0;i<n;i++)
		{
			if(a[x][i]==1&&ju[i]==false)
			{
				ju[i]=true;
				q.push(i);
			}
		}
	}
}
int main()
{
   scanf("%d %d",&n,&m);
   for(int i=0;i<m;i++)
   {
   	int x,y;
   	scanf("%d %d",&x,&y);
   	a[x][y]=1;
   }
   q.push(0);
   ju[0]=true;
   bfs();
   return 0;
}

總結:廣度搜索,搜尋本節點相鄰的所有未訪問的節點,可以用佇列來實現