acm第二十三次圖的遍歷

一、深度優先與廣度優先遍歷
  從圖中某一頂點出發系統地訪問圖中所有頂點,使每個頂點恰好被訪問一次,這種運算操作被稱爲圖的遍歷。爲了避免重複訪問某個頂點,可以設一個標誌數組visited[i],未訪問時值爲false,訪問一次後就改爲true。
  圖的遍歷分爲深度優先遍歷和廣度優先遍歷兩種方法,兩者的時間效率都是O(n*n)。
1.深度優先遍歷
  深度優先遍歷與深搜DFS相似,從一個點A出發,將這個點標爲已訪問visited[i]:=true;,然後再訪問所有與之相連,且未被訪問過的點。當A的所有鄰接點都被訪問過後,再退回到A的上一個點(假設是B),再從B的另一個未被訪問的鄰接點出發,繼續遍歷。
下面給出的深度優先遍歷的參考程序,假設圖以鄰接表存儲
 void dfs(int i) //圖用數組模擬鄰接表存儲,訪問點i
 {
   visited[i] = true; //標記爲已經訪問過
   for (int j = 1; j <= num[i]; j++) //遍歷與i相關聯的所有未訪問過的頂點
   if (!visited[g[i][j]])
   dfs(g[i][j]);
 }

主程序如下:
 int main()
 {
……
memset(visited,false,sizeof(visited));
for (int i = 1; i <= n; i++) //每一個點都作爲起點嘗試訪問,因爲不是從任何
//一點開始都能遍歷整個圖
if (!visited[i])
dfs(i);
……
return 0;
 }
2.廣度優先遍歷
  廣度優先遍歷並不常用,從編程複雜度的角度考慮,通常採用的是深度優先遍歷。
  廣度優先遍歷和廣搜BFS相似,因此使用廣度優先遍歷一張圖並不需要掌握什麼新的知識,在原有的廣度優先搜索的基礎上,做一點小小的修改,就成了廣度優先遍歷算法。

二、一筆畫問題
  如果一個圖存在一筆畫,則一筆畫的路徑叫做歐拉路,如果最後又回到起點,那這個路徑叫做歐拉回路。
  我們定義奇點是指跟這個點相連的邊數目有奇數個的點。對於能夠一筆畫的圖,我們有以下兩個定理。
   定理1:存在歐拉路的條件:圖是連通的,有且只有2個奇點。
   定理2:存在歐拉回路的條件:圖是連通的,有0個奇點。
  兩個定理的正確性是顯而易見的,既然每條邊都要經過一次,那麼對於歐拉路,除了起點和終點外,每個點如果進入了一次,顯然一定要出去一次,顯然是偶點。對於歐拉回路,每個點進入和出去次數一定都是相等的,顯然沒有奇點。
  求歐拉路的算法很簡單,使用深度優先遍歷即可。
  根據一筆畫的兩個定理,如果尋找歐拉回路,對任意一個點執行深度優先遍歷;找歐拉路,則對一個奇點執行DFS,時間複雜度爲O(m+n),m爲邊數,n是點數。
  #include
  #include
  using namespace std;
  #define maxn 101
  int g[maxn][maxn]; //此圖用鄰接矩陣存儲
  int du[maxn]; //記錄每個點的度,就是相連的邊的數目
  int circuit[maxn]; //用來記錄找到的歐拉路的路徑
  int n,e,circuitpos,i,j,x,y,start;
  void find_circuit(int i) //這個點深度優先遍歷過程尋找歐拉路
  {
   int j;
   for (j = 1; j <= n; j++)
   if (g[i][j] == 1) //從任意一個與它相連的點出發
   {
   g[j][i] = g[i][j] = 0;
   find_circuit(j);
   }
   circuit[++circuitpos] = i; //記錄下路徑
  }
   int main()
  {
   memset(g,0,sizeof(g));
   cin >> n >> e;
   for (i = 1; i <= e; i++)
   {
   cin >> x >> y;
   g[y][x] = g[x][y] = 1;
   du[x]++; //統計每個點的度
   du[y]++;
   }
     start = 1; //如果有奇點,就從奇點開始尋找,這樣找到的就是
   for (i = 1; i <= n; i++) //歐拉路。沒有奇點就從任意點開始,
   if (du[i]%2 == 1) //這樣找到的就是歐拉回路。(因爲每一個點都是偶點)
start = i;
   circuitpos = 0;
   find_circuit(start);
   for (i = 1; i <= circuitpos; i++)
   cout << circuit[i] << ’ ';
   cout << endl;
   return 0;
  }

三、哈密爾頓環
  歐拉回路是指不重複地走過所有路徑的迴路,而哈密爾頓環是指不重複地走過所有的點,並且最後還能回到起點的迴路。
  使用簡單的深度優先搜索,就能求出一張圖中所有的哈密爾頓環。
#include
#include
using namespace std;
int start,length,x,n;
bool visited[101],v1[101];
int ans[101], num[101];
int g[101][101];
void print()
{ int i;
for (i = 1; i <= length; i++)
cout << ’ ’ << ans[i];
cout << endl;
}
void dfs(int last,int i)
{
visited[i] = true; //標記爲已經訪問過
v1[i] = true; //標記爲已在一張圖中出現過
ans[++length] = i; //記錄下答案
for (int j = 1; j <= num[i]; j++)
  {
   if (g[i][j]==x&&g[i][j]!=last) //回到起點,構成哈密爾頓環
   {
   ans[++length] = g[i][j];
   print(); //這裏說明找到了一個環,則輸出ans數組。
   length–;
   break;
}
if (!visited[g[i][j]]) dfs(i,g[i][j]);
}
length–;
visited[i] = false;
}
int main()
{
memset(visited,false,sizeof(visited));
memset(v1,false,sizeof(v1));
for (x = 1; x <= n; x++)
//每一個點都作爲起點嘗試訪問,因爲不是從任何一點開始都能找過整個圖的
if (!v1[x]) //如果點x不在之前曾經被訪問過的圖裏。
{
length = 0; //定義一個ans數組存答案,length記答案的長度。
dfs(x);
}
return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章