單源有權圖的最短路徑 Dijkstra演算法(證明不能解決負權邊)7.1.2
阿新 • • 發佈:2018-12-30
單源最短路徑問題,即在圖中求出給定頂點到其它任一頂點的最短路徑。
Dijkstra演算法
假設存在G=<V,E>,源頂點為0,U={0+已確定的最短路徑頂點},dist[i]記錄頂點0到頂點i的最短距離(包括確定的和估算的),path[i]記錄從0到i路徑上的i前面的一個頂點。
U中收錄的是已確定的最短路徑頂點,比如2被U收錄的話就代表dist[2]的值就是頂點0到頂點2的最短路徑,後面操作不需要再更新它。
步驟如下
初始化:dist[i]=0->i,U={0},path[0]=-1。(->這裡表示圖中頂點到另一頂點的權重)
迴圈:
1、路徑中不包括負權邊的情況下未收錄頂點中dist值最小的就是真正的最短距離,收錄到U中 ,用於標記它已經確定了,後面不需要再更新它。
2、上一步確定一個頂點V後,此頂點V的鄰接點W的dist值可能受到影響(除去U收錄的頂點外:dist[W]=MIN(dist[W],dist[V]+V->W),path[W]=V;)。
3、重複以上步驟直到U收錄了所有頂點,i屬於任何頂點時此時dist[i]都表示真正的(已確定)最短距離
證明不能解決負權邊
C語言程式碼實現如下
#include<stdlib.h> #include<stdbool.h> #include<stdio.h> #define INFINITY 65535 /* ∞設為雙位元組無符號整數的最大值65535*/ #define MaxVertexNum 100 /* 最大頂點數設為100 */ typedef int Vertex; /* 用頂點下標表示頂點,為整型 */ typedef int WeightType; /* 邊的權值設為整型 */ typedef char DataType; /* 頂點儲存的資料型別設為字元型 */ bool U[MaxVertexNum]; int dist[MaxVertexNum]; int path[MaxVertexNum]; /* 邊的定義 */ typedef struct ENode *PtrToENode; struct ENode{ Vertex V1, V2; /* 有向邊<V1, V2> */ WeightType Weight; /* 權重 */ }; typedef PtrToENode Edge; /* 鄰接點的定義 */ typedef struct AdjVNode *PtrToAdjVNode; struct AdjVNode{ Vertex AdjV; /* 鄰接點下標 */ WeightType Weight; /* 邊權重 */ PtrToAdjVNode Next; /* 指向下一個鄰接點的指標 */ }; /* 頂點表頭結點的定義 */ typedef struct Vnode{ PtrToAdjVNode FirstEdge;/* 邊表頭指標 */ DataType Data; /* 存頂點的資料 */ /* 注意:很多情況下,頂點無資料,此時Data可以不用出現 */ } AdjList[MaxVertexNum]; /* AdjList是鄰接表型別 */ /* 圖結點的定義 */ typedef struct GNode *PtrToGNode; struct GNode{ int Nv; /* 頂點數 */ int Ne; /* 邊數 */ AdjList G; /* 鄰接表 */ }; typedef PtrToGNode LGraph; /* 以鄰接表方式儲存的圖型別 */ LGraph CreateGraph( int VertexNum ) { Vertex V; /* 初始化一個有VertexNum個頂點但沒有邊的圖 */ LGraph Graph=(LGraph)malloc(sizeof(struct GNode)); Graph->Nv=VertexNum; Graph->Ne=0; /* 初始化鄰接表頭指標 */ /* 注意:這裡預設頂點編號從0開始,到(Graph->Nv - 1) */ for (V=0; V<Graph->Nv; V++) Graph->G[V].FirstEdge = NULL; return Graph; } void InsertEdge( LGraph Graph, Edge E ) { PtrToAdjVNode NewNode; /* 插入邊 <V1, V2> */ /* 為V2建立新的鄰接點 */ NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); NewNode->AdjV = E->V2; NewNode->Weight = E->Weight; /* 將V2插入V1的表頭 */ NewNode->Next = Graph->G[E->V1].FirstEdge; Graph->G[E->V1].FirstEdge = NewNode; /* 若是無向圖,還要插入邊 <V2, V1> */ /* 為V1建立新的鄰接點 */ NewNode = (PtrToAdjVNode)malloc(sizeof(struct AdjVNode)); NewNode->AdjV = E->V1; NewNode->Weight = E->Weight; /* 將V1插入V2的表頭 */ NewNode->Next = Graph->G[E->V2].FirstEdge; Graph->G[E->V2].FirstEdge = NewNode; } LGraph BuildGraph() { LGraph Graph; Edge E; Vertex V; int Nv, i; scanf("%d", &Nv); /* 讀入頂點個數 */ Graph = CreateGraph(Nv); /* 初始化有Nv個頂點但沒有邊的圖 */ scanf("%d", &(Graph->Ne)); /* 讀入邊數 */ if ( Graph->Ne != 0 ) { /* 如果有邊 */ E = (Edge)malloc( sizeof(struct ENode) ); /* 建立邊結點 */ /* 讀入邊,格式為"起點 終點 權重",插入鄰接矩陣 */ for (i=0; i<Graph->Ne; i++) { scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); /* 注意:如果權重不是整型,Weight的讀入格式要改 */ InsertEdge( Graph, E ); } free(E); } /* 如果頂點有資料的話,讀入資料 */ for (V=0; V<Graph->Nv; V++) scanf(" %c", &(Graph->G[V].Data)); return Graph; } void Dijkstra(LGraph Graph,Vertex V){ //初始化 for(int i=0;i<Graph->Nv;i++) {dist[i]=INFINITY;U[i]=false;} PtrToAdjVNode W=Graph->G[V].FirstEdge; for(;W;W=W->Next) dist[W->AdjV]=W->Weight; dist[V]=0;U[V]=true; /////////////// while(true){ // int Min=INFINITY; Vertex j; for(int i=0;i<Graph->Nv;i++) if(Min>dist[i]&&U[i]==false) {Min=dist[i];j=i;} printf("%d\n",Min ); if(Min==INFINITY) break; U[j]=true;//找到最小的dist收錄 printf("%d->%d %d->%d[%d]\n",path[j],j,V,j,dist[j]); // W=Graph->G[j].FirstEdge; for(;W;W=W->Next)//對鄰接點dist進行更新操作 if(dist[W->AdjV]>dist[j]+W->Weight&&U[W->AdjV]==false) {dist[W->AdjV]=dist[j]+W->Weight;path[W->AdjV]=j;} } } int main(){ LGraph Graph=BuildGraph(); Dijkstra(Graph,0); return 0; }
#include<stdlib.h> #include<stdbool.h> #include<stdio.h> #define MaxVertexNum 100 /* 最大頂點數設為100 */ #define INFINITY 65535 /* ∞設為雙位元組無符號整數的最大值65535*/ typedef int Vertex; /* 用頂點下標表示頂點,為整型 */ typedef int WeightType; /* 邊的權值設為整型 */ typedef char DataType; /* 頂點儲存的資料型別設為字元型 */ bool U[MaxVertexNum]; int dist[MaxVertexNum]; int path[MaxVertexNum]; /* 邊的定義 */ typedef struct ENode *PtrToENode; struct ENode{ Vertex V1, V2; /* 有向邊<V1, V2> */ WeightType Weight; /* 權重 */ }; typedef PtrToENode Edge; /* 圖結點的定義 */ typedef struct GNode *PtrToGNode; struct GNode{ int Nv; /* 頂點數 */ int Ne; /* 邊數 */ WeightType G[MaxVertexNum][MaxVertexNum]; /* 鄰接矩陣 */ DataType Data[MaxVertexNum]; /* 存頂點的資料 */ /* 注意:很多情況下,頂點無資料,此時Data[]可以不用出現 */ }; typedef PtrToGNode MGraph; /* 以鄰接矩陣儲存的圖型別 */ MGraph CreateGraph( int VertexNum ) { /* 初始化一個有VertexNum個頂點但沒有邊的圖 */ Vertex V, W; MGraph Graph; Graph = (MGraph)malloc(sizeof(struct GNode)); /* 建立圖 */ Graph->Nv = VertexNum; Graph->Ne = 0; /* 初始化鄰接矩陣 */ /* 注意:這裡預設頂點編號從0開始,到(Graph->Nv - 1) */ for (V=0; V<Graph->Nv; V++) for (W=0; W<Graph->Nv; W++) if(V==W) Graph->G[V][W]=0; else Graph->G[V][W] = INFINITY; return Graph; } void InsertEdge( MGraph Graph, Edge E ) { /* 插入邊 <V1, V2> */ Graph->G[E->V1][E->V2] = E->Weight; /* 若是無向圖,還要插入邊<V2, V1> */ Graph->G[E->V2][E->V1] = E->Weight; } MGraph BuildGraph() { MGraph Graph; Edge E; Vertex V; int Nv, i; scanf("%d", &Nv); /* 讀入頂點個數 */ Graph = CreateGraph(Nv); /* 初始化有Nv個頂點但沒有邊的圖 */ scanf("%d", &(Graph->Ne)); /* 讀入邊數 */ if ( Graph->Ne != 0 ) { /* 如果有邊 */ E = (Edge)malloc(sizeof(struct ENode)); /* 建立邊結點 */ /* 讀入邊,格式為"起點 終點 權重",插入鄰接矩陣 */ for (i=0; i<Graph->Ne; i++) { scanf("%d %d %d", &E->V1, &E->V2, &E->Weight); /* 注意:如果權重不是整型,Weight的讀入格式要改 */ InsertEdge( Graph, E ); } free(E); } /* 如果頂點有資料的話,讀入資料 */ for (V=0; V<Graph->Nv; V++) scanf(" %c", &(Graph->Data[V])); return Graph; } void Dijkstra(MGraph Graph,Vertex V){ //初始化 for(int i=0;i<Graph->Nv;i++) {dist[i]=Graph->G[V][i];U[i]=false;} dist[V]=0;U[V]=true; /////////////// while(true){ // int Min=INFINITY; Vertex j; for(int i=0;i<Graph->Nv;i++) if(Min>dist[i]&&U[i]==false) {Min=dist[i];j=i;} if(Min==INFINITY) break; U[j]=true;//找到最小的dist收錄 printf("%d->%d %d->%d[%d]\n",path[j],j,V,j,dist[j]); // printf("%d\n",j ); for(Vertex W=0;W<Graph->Nv;W++)//對鄰接點dist進行更新操作 if(Graph->G[j][W]!=INFINITY&&dist[W]>dist[j]+Graph->G[j][W]&&U[W]==false) {dist[W]=dist[j]+Graph->G[j][W];path[W]=j;} } } int main(){ MGraph Graph=BuildGraph(); Dijkstra(Graph,0); return 0; }
下一篇多源最短路徑