1. 程式人生 > 其它 >關於用迪傑斯特拉演算法求無向圖最短路問題

關於用迪傑斯特拉演算法求無向圖最短路問題

技術標籤:迪傑斯特拉演算法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][2]=4 表示點V0到點V2的權值為4
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中權值最小的那個點,(標號的點除外)得到V4,對V4標號,然後更改V0通過V1->V2到其它點的路徑得到 distance: {0, 1, 3, 7,4, 10};
第四步:找到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;
}