中國大學MOOC-陳越、何欽銘-資料結構-2018秋——關鍵活動
我的中國大學MOOC-陳越、何欽銘-資料結構-2018秋程式碼倉:https://github.com/617076674/MOOC-DataStructure-2018-Autumn
題目描述:
知識點:關鍵路徑
思路:對邊取相反數,用SPFA演算法求關鍵路徑
題目要求的是所有關鍵活動。也就是說,如果有兩條長度相同關鍵路徑,其上面的活動都應該被羅列出來,但不能羅列相同的路徑。活動的羅列順序不是活動進行的順序,而是根據題目的最後一句話——“任務開始的交接點編號小者優先,起點編號相同時,與輸入時任務的順序相反”。
為了快速定位該活動的輸入順序,我們用一個二維陣列inputSequence[][]儲存各邊對應的輸入順序
為了找到起點,我們還需要統計每一個點的入度,其中入度為0的點才可能是起點。
對所有入度為0的點,我們都以其為起點做SPFA演算法,取其到其他點的最小距離,如果該最小距離比當前記錄的最小距離還要小,我們就需要清空儲存結果邊資訊的resultActivities,將當前路徑所經過的邊加入resultActivities。如果該最小距離與當前記錄的最小距離相等,我們不需要清空resultActivities,直接把當前路徑所經過的邊加入resultActivities即可。
dfs尋找當前路徑所經過的邊時,為了防止向resultActivities重複新增邊
時間複雜度主要來源於多次SPFA演算法,一次SPFA演算法的時間複雜度是O(kM)。空間複雜度是O(N ^ 2)。
C++程式碼:
#include<iostream> #include<vector> #include<queue> #include<set> #include<algorithm> using namespace std; struct node { int v; int len; node(int _v, int _len) { v = _v; len = _len; } }; struct activity { int startV, endV; activity(int _startV, int _endV) { startV = _startV; endV = _endV; } }; int N, M, inDegree[101], d[101], INF = 1000000000, countInq[101], resultMinTime = INF, startPoint; vector<node> graph[101]; //鄰接表形式儲存圖 bool inq[101]; vector<int> tempPath; set<int> pre[101]; int inputSequence[101][101]; //記錄每條邊輸入時的順序 vector<activity> resultActivities; //儲存關鍵路徑上的邊資訊 void init(); bool spfa(int s); void dfs(int nowVisit, bool visited[]); bool cmp(activity a1, activity a2); int main() { scanf("%d %d", &N, &M); //讀取節點數和邊數 bool visited[M]; //標記第i條邊是否已經在結果集裡 fill(inDegree + 1, inDegree + N + 1, 0); int v1, v2, len; for(int i = 0; i < M; i++) { scanf("%d %d %d", &v1, &v2, &len); graph[v1].push_back(node(v2, -len)); inDegree[v2]++; inputSequence[v1][v2] = i; } for(int i = 1; i <= N; i++) { if(inDegree[i] == 0) { //入度為0的點是起點 init(); startPoint = i; //以點i為起點 bool flag = spfa(startPoint); //計算點i到其餘點的最短路徑 if(flag) { int minTime = INF; for(int j = 1; j <= N; j++) { if(j != i && d[j] < minTime) { //尋找從點i到其餘點的最短路徑中的最小值 minTime = d[j]; //更新最小時間資訊 } } if(minTime < resultMinTime) { //如果以i為起點到其餘點的最短路徑的最小值比當前的最小路徑還要小 resultMinTime = minTime; //更新最小路徑資訊 resultActivities.clear(); //清空resultActivities fill(visited, visited + M, false); //標記所有節點未被訪問 for(int j = 1; j <= N; j++) { if(j != i && d[j] == minTime) { dfs(j, visited); } } } else if(minTime == resultMinTime) { for(int j = 1; j <= N; j++) { if(j != i && d[j] == minTime) { dfs(j, visited); } } } } } } if(resultMinTime == INF) { printf("0\n"); return 0; } printf("%d\n", -resultMinTime); //輸出關鍵路徑長度 sort(resultActivities.begin(), resultActivities.end(), cmp); //對結果邊進行排序 for(int i = 0; i < resultActivities.size(); i++) { //輸出結果 printf("%d->%d\n", resultActivities[i].startV, resultActivities[i].endV); } return 0; } void init() { fill(d + 1, d + N + 1, INF); fill(inq + 1, inq + N + 1, false); fill(countInq + 1, countInq + N + 1, 0); for(int j = 1; j <= N; j++) { pre[j].clear(); } } bool spfa(int s) { d[s] = 0; queue<int> q; q.push(s); inq[s] = true; countInq[s]++; while(!q.empty()) { int u = q.front(); q.pop(); inq[u] = false; for(int i = 0; i < graph[u].size(); i++) { int v = graph[u][i].v; int len = graph[u][i].len; if(d[u] + len < d[v]) { d[v] = d[u] + len; pre[v].clear(); pre[v].insert(u); if(!inq[v]) { q.push(v); inq[v] = true; countInq[v]++; if(countInq[v] > N - 1) { return false; } } } else if(d[u] + len == d[v]) { pre[v].insert(u); if(!inq[v]) { q.push(v); inq[v] = true; countInq[v]++; if(countInq[v] > N - 1) { return false; } } } } } return true; } void dfs(int nowVisit, bool visited[]) { tempPath.push_back(nowVisit); if(nowVisit == startPoint) { for(int i = tempPath.size() - 1; i > 0; i--) { int inputNumber = inputSequence[tempPath[i]][tempPath[i - 1]]; if(!visited[inputNumber]) { resultActivities.push_back(activity(tempPath[i], tempPath[i - 1])); visited[inputNumber] = true; } } tempPath.pop_back(); return; } for(set<int>::iterator it = pre[nowVisit].begin(); it != pre[nowVisit].end(); it++) { dfs(*it, visited); } tempPath.pop_back(); } bool cmp(activity a1, activity a2) { if(a1.startV == a2.startV) { return inputSequence[a1.startV][a1.endV] > inputSequence[a2.startV][a2.endV]; } else { return a1.startV < a2.startV; } }
C++解題報告: