圖的最短路徑Dijkstra
阿新 • • 發佈:2019-02-21
dijk 找到 dfs ios aci count set float display
#include <stdio.h> #include <string.h> #include <vector> #include <queue> #include <iostream> using namespace std; const int MAXV = 1000; const int INF = 1000000000; struct Node { int v,dis; }; vector<Node> Adj[MAXV]; int n;//n為頂點數,圖G使用鄰接表實現,MAXV為最大頂點數(點數決定如何遍歷邊)int m;// 邊數(決定輸入什麽樣的圖) int s;//起點 int d[MAXV];//起點到達各個點的最短路徑長度 bool vis[MAXV] = {false};//標記數組,vis[i]==true表示已訪問,初值均為false int pre[MAXV]={0}; //記錄到某一個點的前驅 void Dijkstra(int s) { fill(d,d+MAXV,INF); d[s] = 0;//起點s到達自身的距離為0 //遍歷所有的點 for(int i=0;i<n;i++) { //u為使得d[u]最小的點,MIN存放該最小的d[u]int u = -1,MIN = INF; //每一趟找一個已連通的最短路徑的點出來 for(int j=0;j<n;j++) { if(vis[j] == false && d[j] < MIN) { u = j; MIN = d[j]; } } //找不到小於INF的d[u],說明剩下的頂點和起點s不連通if(u == -1) { return; } //找到了 else { vis[u] = true;//找到則標記成已訪問,每一趟可以確定一個最短點 //遍歷u能到達的所有頂點v,並判斷以u為中轉到j的距離是否比原來的小,如果小則更新 for(int j=0;j < Adj[u].size();j++) { int v = Adj[u][j].v; //以當前最短路徑的點為中轉,看看是否比原來的距離小 ,如果小,則優化d[v] if(vis[v] == false && d[u] + Adj[u][j].dis < d[v]) { d[v] = d[u] + Adj[u][j].dis; //記錄前驅 pre[v] = u; } } } } } //輸出從起點到v的最短路徑 void print(int s,int v) { if(v == s) { cout << s << endl; return; } print(s,pre[v]); cout<< v << endl; } int main() { //頂點個數,邊數,起點編號 cin >> n >> m >> s; int u,v,w; Node tmp; for (int i=0;i<m;i++) { cin >> u >> v >> w; tmp.v = v; tmp.dis = w; Adj[u].push_back(tmp); } Dijkstra(s); for(int i=0;i<n;i++) { cout << d[i] << " "; } cout << endl; print(0,5); return 0; }
練習: PAT A1030 Travel Plan
#include <vector> #include <string> #include <algorithm> #include <iostream> using namespace std; const int MAXV = 510; const int INF = 1000000000; //n為點數,m為邊數,st和ed分別為起點和終點 //G為鄰接矩陣,weight為點權 //d[]記錄最短距離,w[]記錄最大點權之和 int n,m,st,ed,G[MAXV][MAXV],weight[MAXV]; int d[MAXV],w[MAXV]; //vis[i] == true 表示頂點i已訪問 bool vis[MAXV] = {false}; vector<int> pre[MAXV]; void Dijkstra(int s) { fill(d,d+MAXV,INF); d[s] = 0; //每次找出一個最短的點,一共找n個 ,最短的點就是在最短路徑中的點,設置為訪問 for(int i=0;i<n;i++) { int u = -1,MIN = INF; //找最短的點 for(int j=0;j<n;j++) { if(vis[j] == false && d[j] < MIN) { u = j; MIN = d[j]; } } if(u == -1 ) return; vis[u] = true; //看u能到哪些點 ,並以u為中轉,更新其他距離 //以u為中轉,到v for(int v=0;v<n;v++) { if(vis[v] == false && G[u][v] != INF) { if(d[u] + G[u][v] < d[v]) { d[v] = d[u] + G[u][v]; pre[v].clear(); //令v的前驅為u pre[v].push_back(u); } else if(d[u]+G[u][v] == d[v]) { pre[v].push_back(u); } } } } } //求最大值 int optvalue = -INF; //最優路徑及臨時路徑 vector<int> path,tempPath; //路徑數+1 int totalCount = 0; void DFS(int v) { // cout << endl; //到達葉子節點,即起點 if(v == st) { totalCount++; tempPath.push_back(v); int value = 0; for(int i=0;i<tempPath.size();i++) { // value = value + G[ tempPath[i] ][ tempPath[i+1] ]; value = value + weight[tempPath[i]]; } if(value > optvalue) { optvalue = value; path = tempPath; } //回溯 tempPath.pop_back(); return; } //將當期訪問的點加入臨時路徑 tempPath.push_back(v); //訪問所有前驅 for(int i=0;i<pre[v].size();i++) { //遞歸遍歷所有前驅 DFS(pre[v][i]); } tempPath.pop_back(); } int main() { cin >> n >> m >> st >> ed; for(int i=0;i<n;i++) { cin >> weight[i]; } int u,v; fill(G[0],G[0] + MAXV * MAXV,INF); for(int i=0;i<m;i++) { cin >> u >> v; cin >> G[u][v]; G[v][u] = G[u][v]; } Dijkstra(st); DFS(ed); cout << totalCount << " " << optvalue << endl; return 0; }
圖的最短路徑Dijkstra