關於用迪傑斯特拉演算法求無向圖最短路問題
阿新 • • 發佈:2021-01-29
技術標籤:迪傑斯特拉演算法dijkstrac語言c++資料結構
前言
最近在做迪傑斯特拉演算法題,為了防止自己再忘了,所以還是記一下為好(慘)
一、如何用此方法求最短路
摘抄自:https://www.jianshu.com/p/01302376b8d7
如何求圖中V0到V5的最短路徑呢?
第一步,根據圖來建立權值矩陣:
int[][] W = {
{ 0, 1, 4, -1, -1, -1 },
{ 1, 0, 2, 7, 5, -1 },
{ 4, 2, 0, -1, 1, -1 },
{ -1, 7, -1, 0, 3, 2 },
{ -1, 5, 1, 3, 0, 6 },
{ -1, -1, -1, 2, 6, 0 } }; (-1表示兩邊不相鄰,權值無限大)
W[0][3]=-1表示點V0與V3不相鄰,所以權值無限大。
第二步:對V0標號;V0到其它點的路徑得到 distance: {0,1,4,-1,-1,-1}; 找到V0到各點中權值最小的那個點(標號的點除外,-1代表無限大),故得到1即對應的下標1,得到V1;對V1標號,然後更改V0通過V1到其它點的路徑得到 distance: {0, 1, 3, 8, 6, -1};
第三步:找到distance中權值最小的那個點,(標號的點除外)得到V2,對V2標號,然後更改V0通過V1->V2到其它點的路徑得到 distance: {0, 1, 3,8, 4, -1};
第四步:找到distance中權值最小的那個點,(標號的點除外)得到V3,對V3標號,然後更改V0通過V1->V2到其它點的路徑得到 distance: {0, 1, 3, 7, 4, 9};
最後只剩下V5沒有被標號,就找到V5了。結束!
二、程式碼模板與分析
程式碼如下(示例):
/*關於三個陣列:
【1】map陣列存的為點邊的資訊,比如map[1][2]=3,表示1號點和2號點的距離為3
【2】dis陣列存的為起始點與每個點的最短距離,比如dis[3]=5,表示起始點與3號點最短距離為5
【3】vis陣列存的為0或者1,1表示已經走過這個點。*/
void dijkstra()
{
int i,j,v,min;
for(i=0;i<=n;i++)
{
vis[i]=0;//初始化為0,表示開始都沒走過
dis[i]=map[1][i];
}
for(i=1;i<n;i++)
{
min=inf;//無窮大
for(j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]<min)//沒被標記,且它們之間的最短距離小於min
{
min=dis[j];//更新min
v=j;//將此時的下標賦值給v
}
}
vis[v]=1;//標記v這個點,表示已經走過
for(j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]>dis[v]+map[v][j])更新dis的值
dis[j]=dis[v]+map[v][j];
}
}
printf("%d\n",dis[n]);//到n位置的最短路長度
}
2.一般主函式形式
程式碼如下(示例):
int main(){
int i,j,a,b,c;
while(~scanf("%d%d",&m,&n)){
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)
map[i][i]=0;
else map[i][j]=map[j][i]=inf;
for(i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(map[a][b]>c) map[a][b]=map[b][a]=c;//防止有重邊
}
dijkstra();
}
return 0;
}
三、總結(POJ 2387 Til the Cows Come Home)
貝西在田野裡,想回到穀倉,在農夫約翰叫醒她進行早上擠奶之前,儘可能多的睡覺。貝西需要美容覺,所以她想盡快回來。 農夫約翰的田地裡有N (2 <= N <= 1000)個地標,唯一編號為1…n .地標1是穀倉;貝西整天站在其中的蘋果樹林是地標。奶牛在田野裡行走,在地標之間使用不同長度的雙向奶牛步道。貝西對自己的導航能力沒有信心,所以一旦她開始,她總是從頭到尾都在跟蹤。 給定地標之間的步道,確定貝西必須走多遠才能回到穀倉。保證有這樣的路線存在。 *第1行:兩個整數:T和N *第2行…T+1:每行將一條蹤跡描述為三個用空格分隔的整數。前兩個整數是步道經過的地標。第三個整數是軌跡的長度,範圍為1…100.
有N個頂點和T條邊的無向圖,現在要問你從1號頂點到N號頂點的最短距離是多少?
#include <iostream>
#include<cstring>
#include<stdio.h>
using namespace std;
#define inf 1<<29
#define MAXV 1005
int map[MAXV][MAXV];
int n,m;
int dis[MAXV];
bool vis[MAXV];
void dijkstra()
{
int i,j,v,min;
for(i=0;i<=n;i++)
{
vis[i]=0;
dis[i]=map[1][i];
}
for(i=1;i<n;i++)
{
min=inf;//無窮大
for(j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]<min)
{
min=dis[j];
v=j;
}
}
vis[v]=1;
for(j=1;j<=n;j++)
{
if(!vis[j]&&dis[j]>dis[v]+map[v][j])
dis[j]=dis[v]+map[v][j];
}
}
printf("%d\n",dis[n]);
}
int main(){
int i,j,a,b,c;
while(~scanf("%d%d",&m,&n)){
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j)
map[i][i]=0;
else map[i][j]=map[j][i]=inf;
for(i=1;i<=m;i++){
scanf("%d%d%d",&a,&b,&c);
if(map[a][b]>c) map[a][b]=map[b][a]=c;
}
dijkstra();
}
return 0;
}