带权有向图单源最短路径(Dijkstra算法)

2013年9月30日 13点热度 0条评论 来源: arhaiyun

单源最短路径问题,即在图中求出给定顶点到其它任一顶点的最短路径。在弄清楚如何求算单源最短路径问题之前,必须弄清楚最短路径的最优子结构性质。

一.最短路径的最优子结构性质

该性质描述为:如果P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,k和s是这条路径上的一个中间顶点,那么P(k,s)必定是从k到s的最短路径。下面证明该性质的正确性。

假设P(i,j)={Vi....Vk..Vs...Vj}是从顶点i到j的最短路径,则有P(i,j)=P(i,k)+P(k,s)+P(s,j)。而P(k,s)不是从k到s的最短距离,那么必定存在另一条从k到s的最短路径P'(k,s),那么P'(i,j)=P(i,k)+P'(k,s)+P(s,j)<P(i,j)。则与P(i,j)是从i到j的最短路径相矛盾。因此该性质得证。

二.Dijkstra算法

由上述性质可知,如果存在一条从i到j的最短路径(Vi.....Vk,Vj),Vk是Vj前面的一顶点。那么(Vi...Vk)也必定是从i到k的最短路径。为了求出最短路径,Dijkstra就提出了以最短路径长度递增,逐次生成最短路径的算法。譬如对于源顶点V0,首先选择其直接相邻的顶点中长度最短的顶点Vi,那么当前已知可得从V0到达Vj顶点的最短距离dist[j]=min{dist[j],dist[i]+matrix[i][j]}。根据这种思路,

假设存在G=<V,E>,源顶点为V0,U={V0},dist[i]记录V0到i的最短距离,path[i]记录从V0到i路径上的i前面的一个顶点。

1.从V-U中选择使dist[i]值最小的顶点i,将i加入到U中;

2.更新与i直接相邻顶点的dist值。(dist[j]=min{dist[j],dist[i]+matrix[i][j]})

3.知道U=V,停止。

代码实现:

=================Dijkstra.cpp==============================================
/*
*Dijkstra单元最短路径
*@author arhaiyun
*date:2013-09-29
*/
#include "stdafx.h"
#include <iostream>
#include <iomanip>
#include "Graph.h"

using namespace std; 

int main()
{
    int i, n;
    cout << "Please input vertex numbers:";
    cin >> n;
    adjmatrix g;
	
    InitMatrix(g);
    CreateMatrix(g);

    cout << endl << "Adjacent matrix: " << endl;
    PrintMatrix(g, n);

    int *dist = new int [n];
    EdgeNode ** path = new EdgeNode *[n];
    cout << "Start point: ";
    cin >> i;

	Dijkstra(g, dist, path, i, n);
    PrintPath(dist, path, i, n);

	system("pause");
	return 0;
}

=================Graph.h==============================================
#pragma once

#include <fstream>
#define MaxVerNum 20
#define MaxValue 10000

typedef int adjmatrix[MaxVerNum][MaxVerNum];     //邻接矩阵的类型定义

typedef struct Node
{
    int adjvex;
    struct Node * next;
}EdgeNode;        //指针数组path[]基类型定义



//初始化邻接矩阵表示的有向带权图
void InitMatrix(adjmatrix G)
{
	for(int i = 0; i < MaxVerNum; i++)
	{
		for(int j = 0; j < MaxVerNum; j++)
		{
			G[i][j] = MaxValue;
		}
	}
}

//建立邻接矩阵表示的有权带向图(即通过输入图的每条边建立图的邻接矩阵)
void CreateMatrix(adjmatrix G)
{
	int i, j, value;
	cout<<"Input vertex ID and its value:"<<endl;
	
	fstream in("in.txt", ios::in);
	in >> i >> j >> value;
	while( i != -1)
	{
		G[i][j] = value;
		in >> i >> j >> value;
	}
}

//输出邻接矩阵表示的有向带权图(即输出图的每条边)
void PrintMatrix(adjmatrix G, int n)
{
	for(int i = 0; i < n; i++)
	{
		for(int j = 0; j < n; j++)
		{
			if(G[i][j] == MaxValue)
			{
				cout << setiosflags(ios::left) << setw(5) << "Inf";
			}
			else
			{
				cout<< setiosflags(ios::left) << setw(5) << G[i][j];
			}
		}
		cout << endl;
	}
}

// 用到m路径path[m]更新到j路径path[js]
void PathUpdate(EdgeNode* path[], int vertex, int j)
{
	EdgeNode* p;
	p = path[j];
	
	//delete path[j]中记录的路径
	while(p != NULL)
	{
		path[j] = p->next;
		delete p;
		p = path[j];
	}
	
	//首先将到m的路径加入到path[j]
	p = path[vertex];
	EdgeNode *pCurrent, *pNode;
	while(p != NULL)
	{
		pNode = new EdgeNode;
		pNode->adjvex = p->adjvex;
		
		if(path[j] == NULL)
		{
			path[j] = pNode;
		}
		else
			pCurrent->next = pNode;
			
		pCurrent = pNode;
		p = p->next;
	}
	
	//在path[m]基础上添加m->j
	pNode = new EdgeNode;
	pNode->adjvex = j;
	pNode->next = NULL;
	pCurrent->next = pNode;
}

//求单源最短路径的Dijkstral算法
void Dijkstra(adjmatrix GA, int dist[], EdgeNode *path[], int i, int n)
{
	bool *s = new bool[n];
	
	for(int j = 0; j < n; j++)
	{
		if(j == i)
		{
			s[j] = true;
		}
		else
		{
			s[j] = false;
		}
		
		dist[j] = GA[i][j];
		//路径初始化
		if(dist[j] < MaxValue && j != i)
		{
			EdgeNode *pNode = new EdgeNode;
			EdgeNode *pNext = new EdgeNode;
			
			pNode->adjvex = i;
			pNext->adjvex = j;
			
			pNext->next = NULL;
			pNode->next = pNext;
			
			path[j] = pNode;
		}
		else
		{
			path[j] = NULL;
		}
	}
	
	for(int k = 1; k < n -1; k++) //更新n-2次即可得到i到其它n-1个节点的最短路径
	{
		//选取新的最短路径节点进行距离的更新
		int value = MaxValue;
		int vertex = i;
		
		for(int j = 0; j < n; j++)
		{
			if(s[j] == false && dist[j] < value)
			{
				value = dist[j];
				vertex = j;
			}
		}
		
		if( vertex != i)
		{
			s[vertex] = true; //节点值更新完毕,加入到最短节点的行列
		}
		else
		{
			break;
		}
		
		for(int j = 0; j < n; j++)
		{
			if(s[j] == false && GA[vertex][j] + dist[vertex] < dist[j])
			{
				//更新dist[j]的值
				dist[j] = dist[vertex] + GA[vertex][j];
				//更新到j的路径
				PathUpdate(path, vertex, j);
			}
		}
	}
	delete []s;
}
  
 
//输出从源点到每个顶点的最短路径及长度的函数
void PrintPath(int dist[], EdgeNode *path[], int i, int n)
{
	for(int j = 0; j < n; j++)
	{
		if(j != i)
		{
			cout << "[" << i << "," << j << "] min distance:"
				<< dist[j] << ",route path:";
			EdgeNode *	pNode = path[j];
			
			while(pNode != NULL && pNode->next != NULL)
			{
				cout<<pNode->adjvex<<"->";
				pNode = pNode->next;
			}
			if(pNode != NULL)
			{
				cout<<pNode->adjvex;
			}
		}
		cout<<endl;
	}
}

输入:6

in.txt

0 1 10
0 2 12
1 3 16
1 4 25
2 0 4
2 1 3
2 3 12
2 5 8
3 4 7
5 3 2
5 4 10
-1 2 3

0


    原文作者:arhaiyun
    原文地址: https://blog.csdn.net/arhaiyun/article/details/12180421
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。