單源最短路徑 -- Dijkstra演算法
求一個點(源點)到其餘點的最短路徑問題,利用f陣列記錄該節點的父節點,以便以後列印路經的時候,倒著回去的時候列印路徑
#include<iostream> //沒有利用鄰接表儲存圖形結構的演算法,該種方法儲存圖的空間複雜度為O(n*n),遍歷每一條邊的時間複雜度為O(m)
#include<cstdio> //演算法的時間複雜度為O(n*n)
#include<cstdlib>
#include<cstring> //有缺點,就是沒法解決帶有權值是負值的邊
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#include<stack>
#define INF 99999999
#define MAX 20
using namespace std;
int dis[MAX];
int city[MAX][MAX];
int book[MAX];//標記陣列 ,為1代表該 dis[i]為確定的值,也就是真的最短路徑,0代表不確定該路徑是不是最短路徑
int f[MAX];//用來存放該節點的父節點是誰
stack <int> a, b;
int main()
{
int n,m,node;
scanf("%d%d",&n,&m);//n點的個數,m邊的條數
//建立城市之前的關係圖,自身到自身距離為0,兩個城市無法到達則為INF
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(i==j)
city[i][j]=0;
else city[i][j]=INF;
}
int x,y,r;
//輸入題目給出的兩個城市之間的距離
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&r);
city[x][y]=r;
}
scanf("%d",&node);//輸入要求的那個點,求該點到其他點的最短路徑
//初始化dis陣列,裡面存放的是一開始,node點到其餘各點的路徑
for(int i=1;i<=n;i++) {
dis[i]=city[node][i];
if(dis[i] < INF)
f[i] = 1;
}
//初始化book陣列,其實可以把陣列定義main函式外面(即book陣列是全域性變數),book陣列裡面的每個元素都是0
memset(book,0,sizeof(book));
book[node]=1;//自己到本身的距離是0,確定的,所以一開始就把book[node]標記為確定值
//Dijkstra演算法的核心語句
for(int t=1;t<n;t++)//一共需要計算多少次,因為當算到最後一個點的時候,沒有其他選擇了,
{ // 該點的dis[i]就是最短路徑,確切值
int Min=INF,temp;
for(int i=1;i<=n;i++)
{
if(book[i]==0 && dis[i]<Min)
{
Min=dis[i];
temp=i;
}
}
book[temp]=1;
for(int i=1;i<=n;i++)
{
if(!book[i] && city[temp][i]<INF)
{
if(dis[i]>dis[temp]+city[temp][i])//dis[i]代表從1號頂點到i號定點的起始最短路徑,如果經過temp點一轉後
dis[i]=dis[temp]+city[temp][i];//路徑變短了,則更新這兩點之前的最短路徑(此時的最短路徑
f[i] = temp;
} // 不一定是最短的),已經被book標記的dis[i]才是最短路徑,即book[i]=1
}
}
//列印出縮短後的路徑,city[i][j]代表i點到j點的最短距離
for(int i=1;i<=n;i++)
printf("%d ",dis[i]);
printf("\n");
int i = f[6];
a.push(6);
while(i != 1) {
a.push(i);
i = f[i];
}
printf("從1點到6點的最短路徑的走法:\n");
printf("1 ");
while(!a.empty()) {
printf("%d ",a.top());
a.pop();
}
printf("\n");
return 0;
}
/*測試資料
6 9
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
1
程式執行效果
0 1 8 4 13 17
從1點到6點的最短路徑的走法:
1 2 4 3 5 6
*/
(2)利用鄰接表來實現Dijkstra演算法,這是加入了鄰接表,是演算法的時間複雜度降低
建圖的空間複雜度為O(m),遍歷每一條邊的時間複雜度為O(m)
#include<iostream>
#include<cstring>
#include<string>
#include<queue>
#include<algorithm>
#include<map>
#include<iomanip>
#define inf 0x3f3f3f3f
#define maxn 20
using namespace std;
struct node{
int to;
int w;
int next;
};
node edge[maxn];//儲存邊的資訊陣列
int book[maxn];//標記一下該條邊是否已經確定是最小邊了
int head[maxn];//存放i節點的第一條邊在edge陣列裡面的位置
int dis[maxn];//存放num點到每個點的最短距離
int n,m,num;//num為要求的點,即該點到其他點的最短距離
int main()
{
scanf("%d%d%d",&n,&m,&num);
memset(head,-1,sizeof(head));//初始化為-1的是head陣列
memset(dis, inf, sizeof(dis));
memset(book, 0,sizeof(book));
for(int i=0;i<m;i++)//鄰接表的建立過程
{
int front;
scanf("%d%d%d",&front,&edge[i].to,&edge[i].w);
edge[i].next=head[front];
head[front]=i;
}
int k=head[num];//以num為節點,遍歷與它相連的每一條邊
dis[num]=0;//到本身的距離為0
book[num]=1;
while(k!=-1)//也算是對dis陣列初始化的一部分
{
dis[edge[k].to]=edge[k].w;
k=edge[k].next;
}
for(int i=1;i<n;i++)//一共要計算n-1個點,因為剩下最後一個點後,該點的dis距離就是最短的
{
int Min=inf,t;
for(int j=1;j<=n;j++)//遍歷dis陣列裡面的每一條邊,找出離num點最近的點
{
if(book[j]==0 && Min>dis[j])
{
Min=dis[j];
t=j;
}
}
book[t]=1;
int l=head[t];
while(l!=-1)//遍歷t點所連線的每一條邊,看能否鬆弛
{
//edge[l].w代表第l條邊的權值,dis[t]代表num點到t點的最短距離
//edge[l].to代表第l條邊的終點,dis[edge[l].to]代表num點到edge[l].to的距離
if(!book[edge[l].to] && edge[l].w+dis[t]<dis[edge[l].to])
dis[edge[l].to]=edge[l].w+dis[t];
l=edge[l].next;//l邊的下一條邊,即與t點相連的下一條邊
}
}
printf("\n");
for(int i=1;i<=n;i++)
{
printf("%d ",dis[i]);
}
printf("\n");
return 0;
}
/*
輸入資料
6 9 1
1 2 1
1 3 12
2 3 9
2 4 3
3 5 5
4 3 4
4 5 13
4 6 15
5 6 4
輸出結果
0 1 8 4 13 17
*/
(3)繼續對上面的第二種演算法進行優化,在判斷離dis陣列最近距離的點的時候利用堆排序,是該部分演算法的時間複雜度由O(N)降低到O(logN)
相關文章
- 單源最短路徑-Dijkstra演算法演算法
- 圖的單源最短路徑(Dijkstra演算法)演算法
- 0016:單源最短路徑(dijkstra演算法)演算法
- 單源最短路徑複習--Dijkstra演算法和Floyd演算法演算法
- 最短路徑之Dijkstra演算法演算法
- 最短路徑問題 (dijkstra演算法)演算法
- 最短路徑——Dijkstra演算法和Floyd演算法演算法
- 最短路徑—Dijkstra演算法和Floyd演算法演算法
- dijkstra最短路演算法模板(雙源)演算法
- 最短路徑——dijkstra演算法程式碼(c語言)演算法C語言
- 最短路徑—Dijkstra(迪傑斯特拉)演算法演算法
- 求兩點之間最短路徑-Dijkstra演算法演算法
- [最短路徑問題]Dijkstra演算法(含還原具體路徑)演算法
- HDU3790 最短路徑問題【Dijkstra演算法】演算法
- 最短路dijkstra演算法演算法
- 最短路 - Dijkstra 演算法演算法
- 一篇文章講透Dijkstra最短路徑演算法演算法
- python實現Dijkstra演算法之 最短路徑問題Python演算法
- 路徑規劃演算法 - 求解最短路徑 - Dijkstra(迪傑斯特拉)演算法演算法
- 最短路徑--dijkstra演算法、弗洛伊德(Floyd)演算法(帶路徑輸出)演算法
- 《圖論》——最短路徑 Dijkstra演算法(戴克斯特拉演算法)圖論演算法
- 多源最短路徑演算法:Floyd演算法演算法
- 最短路演算法之:Dijkstra 演算法演算法
- 資料結構與演算法——最短路徑Dijkstra演算法的C++實現資料結構演算法C++
- 最短路徑演算法演算法
- 10行實現最短路演算法——Dijkstra演算法
- 最短路演算法詳解(Dijkstra/SPFA/Floyd)演算法
- 最短路之Dijkstra
- 多源最短路徑,一文搞懂Floyd演算法演算法
- 最短路徑(Floyd演算法)演算法
- Djikstra最短路徑演算法演算法
- 最短路-樸素版Dijkstra演算法&堆優化版的Dijkstra演算法優化
- 一個人的旅行 (dijkstra演算法求最短路)演算法
- P4779 【模板】單源最短路徑(標準版)
- 圖論-Dijkstra最短路圖論
- 最短路徑(Dijskra演算法)JS演算法
- 最短路徑演算法總結演算法
- 最短路徑之Floyd演算法演算法