昨天被一道華為實習題目難住了,深深地發現自己的圖基礎不扎實啊,今天先補一把奶——圖的所有路徑輸出
思想跟dfs很像,dfs是不斷向一條路徑遍歷,遍歷一個標記一個,然后要回溯一下,再找沒標記的。它不能經過所有路徑,但是可以經過所有節點。
所有路徑需要按照這個思路(copy一下):
求下圖中節點0到節點5的所有路徑:
1、 我們建立一個存儲結點的棧結構,將起點0入棧,將結點0標記為入棧狀態;
2、 從結點0出發,找到結點0的第一個非入棧狀態的鄰結點2,將結點2標記為入棧狀態;
3、 從結點2出發,找到結點2的第一個非入棧狀態的鄰結點4,將結點4標記為入棧狀態;
4、 從結點4出發,找到結點4的第一個非入棧狀態的鄰結點5,將結點5標記為入棧狀態;
5、 棧頂結點5是終點,那么,我們就找到了一條起點到終點的路徑,輸出這條路徑;
6、 從棧頂彈出結點5,將5標記為非入棧狀態;
7、 現在棧頂結點為5,結點5沒有除終點外的非入棧狀態的結點,所以從棧頂將結點5彈出;
8、現在棧頂結點為4,結點4除了剛出棧的結點5之外,沒有非入棧狀態的相鄰結點,那么我們將結點4出棧;
9、現在棧頂為結點2,結點2除了剛出棧的結點4之外,沒有非入棧狀態的相鄰結點,那么我們將結點2出棧;
10、現在棧頂結點為0,從節點0出發,找到結點0的第一個非入棧狀態的鄰結點1,將結點1標記為入棧狀態;一直查找到終點節點5。
11、重復步驟7-11,就可以找到從起點3到終點6的所有路徑;
12、棧為空,算法結束。
以上1-5為典型的dfs的一個子過程——不撞南牆不回頭的一直遍歷到目的!
接下來到頭了,就要回溯了(這就涉及到遞歸),到上一個節點,然后以上一個節點為開始繼續不撞南牆不回頭。
說到這,應該就很明白了。
我們需要幾個部分:
1.棧
2.打印棧函數
3.檢查接下來入棧的值是否已經在棧內的函數
4.很像dfs的一個函數
又到了我最喜歡的上代碼環節:
#include <iostream> #include <fstream> #include <vector> #include <algorithm> #include <string> #include <stack> using namespace std; int map[6][6] = { { 0, 2, 10, 5, 3, -1 }, { -1, 0, 12, -1, -1, 10 }, { -1, -1, 0, -1, 7, -1 }, { 2, -1, -1, 0, 2, -1 }, { 4, -1, -1, 1, 0, -1 }, { 3, -1, 1, -1, 2, 0 } }; stack<int> s; void Print(stack<int> s) { while (!s.empty()) { cout << s.top() << " "; s.pop(); } cout << endl; } bool findval(stack<int> s, int val) { while (!s.empty()) { if (s.top() == val) { return true; } s.pop(); } return false; } void AllPath(int start, int end) { if (start == end) { Print(s); s.pop(); return; } for (int i = 0; i < 6; i++) { if (map[start][i] != -1 && start != i && findval(s, i) == false) { s.push(i); AllPath(i, end); } } //這一步很重要!對於start節點遍歷所有連接,如果遍歷完,就要把stack中的start節點pop掉,否則會無限遞歸 s.pop(); } int main() { int X = 0, Y = 4; s.push(X); while (!s.empty()) { AllPath(X, Y); } return 0; }
鄰接矩陣中-1表示不通,0表示沒有(也可以認為不通吧,反正沒有自己指向自己的)。
這樣可以顯示所有要走的路徑。