內容總結 自《啊哈!算法!》
作為一個都大二的了一個菜雞,做題的時候DFS怎么可以不會呢!!!
作為一個都大二了的(!!!)菜雞....《啊哈算法》這本書第四章的搜索,開始那里我就沒看懂,就跑來看第五章了。結果這個理解起來方便一些....總結摘抄一下給遠方的不知名網友and for myself。
以下語言有不嚴謹之處請多包涵,先理解重要。
深度搜索算法,就是對於一個圖(圖自己瞎畫的 太丑) 如下圖所示,給這些圓圈標號。
然后我們遍歷的時候,是“優先深度” ,先從一條路走到黑走不動了再換條道繼續一條路走到黑。即先從1開始,走到2,走到5. 然后走不動了就先回去,先回到2,發現還有6可以走,然后又走到6了。然后又走不動了。便回到2,但是2的所有支路已經都被訪問過了,那就再往回走一個,走到1。 回到1以后,2這條道已經走完了,就走到3,再走到7,走不動了再回到3,3沒有別的支路可以走了就再回到1,然后再走4
那么上圖的訪問順序是(不算重復的頂點):1 2 5 6 3 7 4
如果一條道走完了,比如說從2走到5,走完了,就要回到上一個路口頂點2。從5到2的過程稱為回溯。
那么如何存儲一個圖呢?我們用一個二維數組arr來存儲:
如上兩個圖所示,二維數組中第i行第j列表示的就是頂點i到頂點j是否有邊。1表示有邊,空着的就是沒有邊(在編程時可以將其賦值為9999,畫圖太麻煩我就省去了) ,二維數組行和列相等的我賦值為0.
能看到,上面的這個圖是關於主對角線對稱的,這是因為這個圖是個‘無向圖’。也就是這個圖的邊沒有方向,從1到2和從2到1是一樣的,所以 arr[ 2 ] [ 1 ] = arr[ 1 ][ 2 ] = 1。
以下是代碼實現:
其中,book[ ] 這個數組一開始全部賦初值為0,表示未被訪問過。被訪問賦值為1。
還有一個需要知道的小知識點,就是我的代碼內又兩個return,第一個return表示函數結束,第二個return表示返回上一個dfs()函數,這是遞歸函數的特殊用法。比如:現在是dfs(5),執行代碼時遇到了代碼中第二個return,然后就會返回上一個執行的dfs()函數,這就變成了dfs(2),這個過程就是回溯。
1 void dfs(int cur)//cur是當前在的頂點的編號 2 { 3 printf("%d ",cur);//按順序打印出遍歷過的點 4 sum++;//sum是全局變量,初值為0。每訪問一個點,sum++。 5 if(sum==n) 6 return ;//n為全局變量,是總共點的數量。若sum==n,便是點都訪問完了,就退出函數。 7 8 for(int i=1;i<=n;i++)//從1號點到n號點依次嘗試,看看誰與cur點相連着 9 { 10 if(arr[cur][i]==1&&book[i]==0)//若這個點沒有被訪問過並且與cur相連 11 { 12 book[i]=1;//把這個點標記為已訪問 13 dfs(i);//遞歸,繼續從這個點再繼續深入遍歷 14 } 15 } 16 return ;//當與cur相連的所有點都已被訪問過了,就返回到上一個dfs() 17 }
完整代碼如下:
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 5 int book[101],sum,n,arr[101][101]; 6 7 void dfs(int cur)//cur是當前在的頂點的編號 8 { 9 printf("%d ",cur);//按順序打印出遍歷過的點 10 sum++;//sum是全局變量,初值為0。每訪問一個點,sum++。 11 if(sum==n) 12 return ;//n為全局變量,是總共點的數量。若sum==n,便是點都訪問完了,就退出函數。 13 14 for(int i=1;i<=n;i++)//從1號點到n號點依次嘗試,看看誰與cur點相連着 15 { 16 if(arr[cur][i]==1&&book[i]==0)//若這個點沒有被訪問過並且與cur相連 17 { 18 book[i]=1;//把這個點標記為已訪問 19 dfs(i);//遞歸,繼續從這個點再繼續深入遍歷 20 } 21 } 22 return ;//當與cur相連的所有點都已被訪問過了,就返回到上一個dfs() 23 } 24 25 26 27 int main() 28 { 29 sum=0; 30 int m,a,b; 31 cin>>n>>m;//m表示有幾條邊 n表示有幾個點 32 for(int i=1;i<=n;i++){ 33 for(int j=1;j<=n;j++){ 34 if(i==j) 35 arr[i][j]=0; 36 else 37 arr[i][j]=9999999;//把沒有邊相連的標記為999999 38 } 39 } 40 41 //讀入頂點之間的那些邊 42 for(int i=0;i<m;i++) 43 { 44 cin>>a>>b; 45 arr[a][b]=1; 46 arr[b][a]=1;//由於時無向圖,所以兩個都要標記。在前面我說過了 47 } 48 book[1]=1;//從1號頂點出發。標記1號頂點已經被訪問 49 dfs(1); 50 51 getchar();getchar(); 52 53 54 return 0; 55 }
ok fine 那么簡單圖遍歷就說完了 下次繼續寫