單源最短路
阿新 • • 發佈:2020-12-05
dijkastra寫法
鄰接矩陣
#include <bits/stdc++.h> using namespace std; #define int long long #define r read() const int maxn = 1e4; const int INF = 0x3f3f3f3f; int n,m,q; int G[maxn][maxn]; bool vis[maxn];/// 標記位 int close[maxn];///最近距離所在的終點 int dis[maxn];///最近的距離 void out(int x) { if(x==q){cout<<x<<' ';return ;} out(close[x]); cout<<x<<' '; } signed main() { ios::sync_with_stdio(false); cin.tie(0); cout.tie(0); memset(G,INF,sizeof(G));/// 按照邏輯含義 不存在的邊的長度為無窮大 但是邊相同的會被覆蓋 memset(vis,false,sizeof (vis)); memset(close,-1,sizeof(close)); ///freopen("1.txt","r",stdin); ///freopen("2.txt","w",stdout); cin>>m>>n>>q;///n條邊 m個頂點 for (int i=0;i<n;++i) { int u; int v; int w; cin>>u>>v>>w; G[u][v] = w; } for (int i=1;i<=m;++i) { dis[i] = G[q][i];/// 首次更新 確立v1為永久點 if (!vis[i] && dis[i]!=INF) close[i] = q;/// 和當前永久點相連最近 } int idx = q; vis[q] = true; dis[q] = 0; for (int i=1;i<m;++i) { int mine = INF; for (int k=1;k<=m;++k) { if(!vis[k]&&dis[k]<mine) { mine = dis[k]; idx = k; } } /// 找出當前的最小臨時點 設為永久點 vis[idx] = true;/// 設為永久點 進行標記 /// cout<<close[idx]<<' '<<idx<<endl; for (int j=1;j<=m;++j) { if (!vis[j]&&dis[idx]+G[idx][j] < dis[j])/// 更新永久點相連的頂點 { close[j] = idx; //sum -= dis[j]; dis[j] = dis[idx]+G[idx][j]; //sum += dis[j]; } } } /*for (int i=1;i<=m;++i) { cout<<close[i]<<' '; }*/ ///puts(""); out(m); return 0; } /* dijkstra演算法 本種寫法針對於無重邊的情況 ,主要採用的思想是貪心 每次利用上一次得到的永久點進行更新 首先將起始點設為永久點 然後對於和永久點相連的邊進行更新 更新最短的距離dis[i] 然後對於剩餘的臨時點查詢其中的最小值設為新的永久點 用當前的永久點進行更新 如此往復 每次更新到當前最近的距離的頂點 對於記錄vq到所有點的最短路徑,進行回溯 */
鄰接表寫法
#include <bits/stdc++.h> using namespace std; #define int long long #define r read() const int maxn = 1e4; const int INF = 0x3f3f3f3f; int n,m,q; bool vis[maxn]; int dis[maxn];/// 儲存從開始位置噹噹前下標節點的最短距離 int close[maxn]; ///儲存最短距離最近的頂點編號 struct vex_edge /// 頭節點結構 { struct edge_Node *first_Node;/// 儲存第一個邊節點 }G[maxn]; struct edge_Node { int idx;/// 跟G[i]-idx 表示 從i到idx的邊 int weight;/// 權重 struct edge_Node * next_edge;/// 下一個邊節點 }; void out(int x) { if(x==q){cout<<x<<' ';return ;} out(close[x]); cout<<x<<' ';/// 逆序輸出 } void init()/// 初始化 { memset(vis,false,sizeof(vis)); memset(close,-1,sizeof(close)); memset(dis,INF,sizeof(dis)); for (int i=1;i<=m;++i) G[i].first_Node = NULL;/// 頭節點首先為空 此時是不存在的頭節點 只是一個指標 /// 有需要也可以自行弄一個頭節點 } signed main() { cin>>m>>n>>q;/// n條邊 m個節點 q是開始出發的起點 init();/// 初始化 for (int i=1;i<=n;++i) { int u,v,w; cin>>u>>v>>w; struct edge_Node*p; p = (edge_Node*)malloc(sizeof(edge_Node)); p->idx = v; p->weight = w; p-> next_edge = G[u].first_Node; /// 插入操作 將所有的鏈節點放到p之後 G[u].first_Node = p; } /* for (int i=1;i<=m;++i) { struct edge_Node *op; op = G[i].first_Node; cout<<i<<' '; while (op!=NULL) { cout<<op->idx<<' '<<op->weight<<' '; op = op ->next_edge; G[q].first_Node; } cout<<endl; } */ struct edge_Node *op; op = G[q].first_Node; while (op != NULL) /// 找出跟q相連的邊節點 { dis[op->idx] = op->weight; close[op->idx] = q; ///cout<<op->weight<<endl; op = op ->next_edge; } int id = q; vis[q] = true; dis[q] = 0; /// close[q] = q;/// 最後回溯路徑的基礎條件 for (int i=1;i<m;++i) { int mine = INF; for (int k=1;k<=m;++k) { if(!vis[k]&&dis[k]<mine) { mine = dis[k]; id = k; } } /// 找出當前的最小臨時點 設為永久點 vis[id] = true;/// 設為永久點 進行標記 ///cout<<id<<endl; /// cout<<close[idx]<<' '<<idx<<endl; struct edge_Node *T; T = G[id].first_Node; while (T!=NULL) { if (!vis[T->idx]&&dis[T->idx] > (dis[id]+(T->weight))) { close[T->idx] = id; dis[T->idx] = dis[id] +T->weight; /// cout<<T->idx<<' '<<dis[T->idx]<<endl; } T = T->next_edge; } } for (int i=1;i<=m;++i) cout<<close[i]<<' '; puts(""); for (int j=1;j<=m;++j) out(j),puts("");/// 輸出每一條最短路徑 return 0; }