1. 程式人生 > >Dijkstra演算法1:鄰接矩陣表示

Dijkstra演算法1:鄰接矩陣表示

從某個源點到其餘各頂點的最短路徑問題:

Dijkstra演算法解決了有向圖G=(V,E)上帶權的單源最短路徑問題,但是要求所有邊的權值非負(原因後面敘述)。

Dijkstra演算法思想為:設 G = (V, E) 是一個帶權有向圖,把圖中頂點集合 V 分成兩組,第一組為以求出最短路徑頂點的集合(用S表

,初始時 S 中只有一個源點,以後每求得一條最短路徑 , 就將其加入到集合 S 中,直到全部頂點都加入到 S 中,演算法就結束了)

,第二組為其餘未確定最短路徑的頂點的集合(用U表示),按最短路徑長度的遞增次序依次把第二組的頂點加入 S 中。在加入的過

程中,總保持從源點 v 到 S 中各頂點的最短路徑長度不大於從源點 v 到 U 中任何頂點的最短路徑長度。此外,每個頂點對應一個距

離,S 中的頂點的距離就是從 v 到此頂點的最短路徑長,U中的頂點的距離,是從 v 到此頂點只包括 S 中的頂點為中間頂點的當前最短

路徑長度。虛擬碼:

DIJKSTRA(G, w, s)
1  INITIALIZE-SINGLE-SOURCE(G, s)//初始源
2  S ← Ø
3  Q ← V[G]
4  while Q ≠ Ø
5      do u ← EXTRACT-MIN(Q)//找出Q中距離最短路徑
6         S ← S ∪{u}
7         for each vertex v ∈ Adj[u]
8             do RELAX(u, v, w)//鬆弛操作

單源最短路徑演算法中使用了鬆弛(relaxation)操作。對於每個頂點v∈V,都設定一個屬性d[v],用來描述從源點s到v的最短路徑上權值的上界,稱為最短路徑估計(shortest-path estimate)。π[v]代表S到v的當前最短路徑中v點之前的一個點的編號。一次鬆弛操作可以減小最短路徑估計的值d[v]。

每個單源最短路徑演算法中都會呼叫INITIALIZE-SINGLE-SOURCE,然後重複對邊進行鬆弛的過程。另外,鬆弛是改變最短路徑和前趨的唯一方式。下面的虛擬碼對邊(u,v)進行了一步鬆弛操作。

RELAX(u, v, w)
  if(d[v]>d[u]+w(u,
v)) then d[v]←d[u]+w(u,v) π[v]←u
程式例項:

在每年的校賽裡,所有進入決賽的同學都會獲得一件很漂亮的t-shirt。但是每當我們的工作人員把上百件的衣服從商店運回到賽場的時候,卻是非常累的!所以現在他們想要尋找最短的從商店到賽場的路線,你可以幫助他們嗎?

輸入包括多組資料。每組資料第一行是兩個整數N、M(N<=100,M<=10000),N表示成都的大街上有幾個路口,標號為1的路口是商店所在地,標號為N的路口是賽場所在地,M則表示在成都有幾條路。N=M=0表示輸入結束。接下來M行,每行包括3個整數A,B,C(1&lt;=A,B<=N,1<=C<=1000),表示在路口A與路口B之間有一條路,我們的工作人員需要C分鐘的時間走過這條路。
輸入保證至少存在1條商店到賽場的路線。

輸出:

對於每組輸入,輸出一行,表示工作人員從商店走到賽場的最短時間

示例:

2 1
1 2 3
3 3
1 2 5
2 3 5
3 1 2
0 0

#include<cstdio>
#include <climits>
#include <iostream>
using namespace std;
const int inf = INT_MAX>>1;
const int NV = 101;
int dis[NV];
int map1[NV][NV];
bool mark[NV];
int m,n;
void dijkstra(int src)
{
    int i, k, j,minf;
for( i = 0; i < n; ++i)
{
    mark[i] = false;
    dis[i] = map1[src][i];
}
dis[src] = 0;
mark[src] = true;
for( i = 1; i < n; ++i)
{
minf = inf;
k = src;
for(j = 0; j < n; ++j)
{
    if(dis[j] < minf && (!mark[j]))
    {
        minf = dis[j];
        k = j;
    }
}
mark[k] = true;
for(j = 0; j < n; j++)
{
    int temp = dis[k] + map1[k][j];
    if(!mark[j] && temp < dis[j])
        dis[j] = temp;
}
}
 return;
}
int main()
{
    while(scanf("%d %d",&n,&m), m || n)
    {
      for(int i = 0; i < n; ++i)
      {
          map1[i][i] = inf;
      for(int j = i + 1; j < n; j++)
      {
          map1[i][j] = inf;
          map1[j][i] = inf;
      }
      }
while(m--)
{
int v1,v2,t;
scanf("%d %d %d", &v1, &v2, &t);
if(map1[v1 - 1][v2 - 1] > t)
{
map1[v1 - 1][v2 - 1] = t;
map1[v2 - 1][v1 - 1] = t;
}
}
 dijkstra(0);
 printf("%d",dis[n - 1]);
    }
    return 0;
}

對於迪傑斯特拉演算法所有邊的權值非負是因為  Dijkstra由於是貪心的,每次都找一個距源點最近的點(dmin),然後將該距離定為這個點到源點的最短路徑(d[i] ← dmin);但如果存在負權邊,那就有可能先通過並不是距源點最近的一個次優點(dmin’),再通過這個負權邊 L (L < 0),使得路徑之和更小(dmin’ + L < dmin),則 dmin’ + L 成為最短路徑,並不是dmin,這樣Dijkstra就被囧掉了。

相關推薦

Dijkstra演算法1鄰接矩陣表示

從某個源點到其餘各頂點的最短路徑問題: Dijkstra演算法解決了有向圖G=(V,E)上帶權的單源最短路徑問題,但是要求所有邊的權值非負(原因後面敘述)。 Dijkstra演算法思想為:設 G = (V, E) 是一個帶權有向圖,把圖中頂點集合 V 分成兩組,第一組為以

圖的鄰接矩陣表示與最短路徑演算法Dijkstra )程式碼實現

#include <stdio.h> #define MAX_VERTEX_NUM 20 //最大頂點個數 typedef int VRTYPE, InfoType; typedef enum {DG, DN, UDG, UD

最短路徑(二)—Dijkstra演算法(通過邊實現鬆弛鄰接矩陣

上一節通過Floyd-Warshall演算法寫了多源節點最短路徑問題: 這一節來學習指定一個點(源點)到其餘各個頂點的最短路徑。也叫做“單源最短路徑”Dijkstra。 例如求下圖中1號頂點到2、3、4、5、6號頂點的最短路徑。 用二維陣列e儲存頂點之間邊的關係,初

Dijkstra演算法-最短路徑-鄰接矩陣表示

圖結構練習——最短路徑 Time Limit: 1000MS Memory Limit: 65536KB Problem Description  給定一個帶權無向圖,求節點1到節點n的最短路徑。 Input  輸入包含多組資料,格式如下。 第一行包括兩

圖相關(三)圖的鄰接矩陣表示(C++)及最最小生成樹演算法(prim和kruskal)

一.測試用圖 鄰接矩陣表示: //prim注意是無向圖 vector<vector<int>> p(6, vector<int>(6, INF));//類似dijikstra,沒有邊的點設為INF p[0][1] = 10;

圖相關(二)圖的鄰接矩陣表示(C++)及最短路徑演算法

一.Dijikstra演算法 注意:計算最短路徑時,需要把鄰接矩陣中沒有邊的位置初始化為無窮大;此處以INF表示,INF可以取0x3f3f3f3f,不能直接設為INT_MAX(因為做加法時會上溢)。 測試用圖: 其鄰接矩陣表示為: vector<vector<int

資料結構 圖的鄰接表示轉換成鄰接矩陣表示演算法

圖的鄰接表表示轉換成鄰接矩陣表示的演算法。 下面這個是有向圖鄰接表表示轉換成鄰接矩陣 #include <stdio.h> #include <string.h> #include <stdlib.h> int a[100][100];

圖的基本概念;圖的儲存表示鄰接矩陣鄰接

無向圖 邊(vi,vj) 有向圖 弧 有向完全圖和無向完全圖 有向圖最多有n(n-1)條邊,且有n(n-1)條邊的有向圖為有向完全圖。 無向圖最多有n(n-1)/2條邊,且有n(n-1)/2條邊

無向圖的表示鄰接矩陣鄰接

這裡將一個無向圖用鄰接表和鄰接矩陣表示。 輸入:頂底個數n,圖中的各個邊(用兩個頂點表示)。 輸出:這個無線圖的鄰接矩陣和鄰接表,其中鄰接表中的連結按元素大小升序排列。 先給出一個例子說明。假設有無向圖如下,則其鄰接矩陣和鄰接表如提示框中所示(其實就是下面程式的輸出)。

(c++)資料結構與演算法之圖鄰接矩陣、深度廣度遍歷、構造最小生成樹(prim、kruskal演算法

//圖的鄰接矩陣實現 //廣度遍歷bfs和深度遍歷dfs //構造最小生成樹的prim、kruskal演算法 #include <iostream> #include<stack> #include<queue> #define WEI

鄰接矩陣表示

兩種 http down leetcode img mas gen eat cnblogs 圖常用兩種方式表示,鄰接矩陣、鄰接表。 0、結構初始化 struct GraphNode { int Nv; /* 頂點數 */ int

每週一演算法(1)漢諾塔

首先漢諾塔是使用遞迴一個非常經典的例子, 歷史故事說了也沒用,我們想象原理。 前提,三根柱子ABC,將A上的盤子數按順序挪到C,每次只能一個 1. 一個盤子,A->C 2. 兩個盤子  A->B, A->C, B->C 3. 大於兩個盤子,那

1-7 鄰接矩陣儲存圖的深度優先遍歷 (10 分)

試實現鄰接矩陣儲存圖的深度優先遍歷。 函式介面定義: void DFS( MGraph Graph, Vertex V, void (*Visit)(Vertex) ); 其中MGraph是鄰接矩陣儲存的圖,定義如下: typedef struct GNode *PtrToGNod

Dijkstra演算法1.1(模板)

輸入給了你一個n個節點的無向圖的鄰接矩陣的下三角部分.要求你輸出從第0個點到所有其他點的距離的最大值 #include<cstdio> #include<cstring> #include<vector> #include<queu

C++ 圖的鄰接矩陣表示以及深度優先和廣度優先遍歷

Node.h 宣告頂點類 #pragma once class Node { public: Node(char data=0); char m_cData; bool m_bIsVisited; }; Node.cpp 實現頂點的成員以及操作函式 #incl

圖相關(一)圖的鄰接矩陣表示(C++)及圖的遍歷

一.圖的鄰接矩陣表示法 struct graph { vector<vector<int>> cost;//鄰接矩陣 vector<string> vertex;//頂點的值,用string較好,節點的名字可以是v1,v

LeetCode演算法1java 兩數之和

問題: 給定一個整數陣列 nums 和一個目標值 target,請你在該陣列中找出和為目標值的那 兩個 整數,並返回他們的陣列下標。 你可以假設每種輸入只會對應一個答案。但是,你不能重複利用這個陣列中同樣的元素。 示例: 給定 nums = [2, 7, 11, 15],

演算法概念大O表示法/小o表示法/Ω/Θ

對於任何數學函式,這三個記號可以用來度量其“漸近表現”,即當趨於無窮大時的階的情況,這是演算法分析中非常重要的概念。大家可以把它們分別想象成≤、≥和,分別估計了函式的漸近上界、漸近下界和準確界。誠然,漸近關係和確切大小關係是有區別的,但當問題規模很大時,忽略這種區別能大大降低演算法分析的難度。 下面我

判斷無向圖圖的連通性,鄰接矩陣表示

 在古老的魔獸傳說中,有兩個軍團,一個叫天災,一個叫近衛。在他們所在的地域,有n個隘口,編號為1..n,某些隘口之間是有通道連線的。其中近衛軍團在1號隘口,天災軍團在n號隘口。某一天,天災軍團的領袖巫妖王決定派兵攻打近衛軍團,天災軍團的部隊如此龐大,甚至可以填江過河。但是巫妖王不想付出不必要的代價,他想知道

圖 | 儲存結構鄰接矩陣及C語言實現

使用圖結構表示的資料元素之間雖然具有“多對多”的關係,但是同樣可以採用順序儲存,也就是使用陣列有效地儲存圖。 鄰接矩陣 鄰接矩陣(Adjacency Matrix),又稱 陣列表示法,儲存方式是用兩個陣列來表示圖: 一個一維陣列儲存圖中頂點本身資訊