程式設計師面試金典: 9.4樹與圖 4.2給定有向圖,設計一個演算法,找出兩個節點之間是否存在一條路徑。
阿新 • • 發佈:2019-01-08
#include <iostream> #include <stdio.h> #include <vector> #include <queue> using namespace std; /* 問題:給定有向圖,設計一個演算法,找出兩個節點之間是否存在一條路徑。 分析:有向圖,無非是沒有頂點的樹,需要考慮頂點和邊。 圖的兩種建立方式:鄰接矩陣,鄰接表。 找出兩個節點之間是否存在一條路徑。Dijstra:兩點之間最短路徑,Flord是任意兩點最短路徑。 還有連通圖的最短路徑。 圖的遍歷有:深度優先和廣度優先。 輸入: 5(結點個數,元素下標從1開始) 5(有向邊個數) 1(起始結點編號) 5(結束結點編號) 1 2(有向邊,從結點1指向節點2) 1 3 2 3 2 4 3 5 5 4 1 5 1 2 1 3 2 3 2 4 輸出: exist path not exist path 未能解出 關鍵: 1 迪傑斯特拉演算法是求指定點到其他節點的單源最短路徑(但必須是無向圖),所以此題不能用dijkstra演算法 2 只需要從兩個節點中任意一個節點出發,繼續遍歷,訪問過的節點標記為已經訪問,即可。 之所以沒想到是因為:考慮圖的遍歷的時候想到如果是非連通圖,認為就無法繼續向下遍歷了。就排除了圖的遍歷。 實際上:圖遍歷過程中如果到一次遍歷結束後,包含了另外一個節點,說明兩者連通;否則,不連通。 之所以考慮到dijkstra演算法是因為想到求指定點到其他節點單元最短路徑,但是沒考慮到迪傑斯特拉演算法需要無向圖, 否則,有向圖連線中存在無法連通情況,單源最短路徑不一定能求出。 3 記住遍歷就兩種:廣度優先(佇列+結構體) ,深度優先(遞迴) */ const int MAXSIZE = 1000; typedef struct Node { Node(int value):_value(value){} int _value; }; //圖的遍歷 bool isTwoNodeInPath(int beginNode , int endNode , vector<Node> vecNode[MAXSIZE + 1]) { int g_visit[MAXSIZE]; memset(g_visit , 0 , sizeof(int) * MAXSIZE); //設定所有節點為 Node node(beginNode); g_visit[beginNode] = 1; queue<Node> queueNode; queueNode.push(node); while(!queueNode.empty()) { //彈出當前節點 Node curNode = queueNode.front(); queueNode.pop(); int value = curNode._value; int size = vecNode[value].size(); //遍歷所有連線的節點並壓入到佇列中 for(int i = 0 ; i < size; i++) { Node tempNode = vecNode[value].at(i); //壓入之前,如果該結點已經被訪問,則不壓入 if(g_visit[tempNode._value] == 1) { continue; } g_visit[tempNode._value] = 1; queueNode.push(tempNode); } } //佇列為空,遍歷結束,只需要檢查另一個節點如果已經訪問過,說明連通 if( g_visit[endNode] == 1 ) { return true; } else { return false; } } int main(int argc, char* argv[]) { int nodeNum ; int edgeNum; int beginNode; int endNode; int frontNode; int backNode; while(cin >> nodeNum >> edgeNum) { cin >> beginNode >> endNode; vector<Node> vecNode[MAXSIZE + 1]; //到這裡N個節點對應的鄰接表都建立好了,每個節點的鄰接表實際上就是一個向量,每個節點對應於林劫鏢中向量下標 //有向圖的鄰接表無需複製雙份,存在鄰接關係,只需要將被指向節點放入節點向量中 for(int i = 0 ; i < edgeNum ; i++) { cin >> frontNode >> backNode; if(frontNode < 0 || backNode < 0) { continue; } Node node(backNode); vecNode[frontNode].push_back(node); } bool isPath = isTwoNodeInPath(beginNode , endNode , vecNode); if(isPath) { cout << "exist path" << endl; } else { cout << "no exist path" << endl; } } getchar(); return 0; }