藍橋杯第三次培訓之圖的深度遍歷和廣度遍歷
圖的遍歷
圖的遍歷是指從圖中某一個頂點出發訪遍圖中其餘頂點,且使每一個頂點僅被訪問一次
圖的遍歷演算法是求解圖的連通性問題、拓撲排序和求關鍵路徑等演算法的基礎
由於圖結構本身的複雜性,所以其遍歷也較複雜,主要體現在:
(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;
}
總結:廣度搜索,搜尋本節點相鄰的所有未訪問的節點,可以用佇列來實現