Dijkstra 算法介绍以及实现

Dijkstra算法的具体实现方法为:


1. 设置两个顶点的集合T和S:
a) S中存放已找到最短路径的顶点,初始时,集合S中只有一个顶点,即源点v0;
b) T中存放当前还未找到最短路径的顶点;

2.在T集合中选取当前长度最短的一条最短路径(v0,…,vk),从而将vk加入到顶点集合S中,并修改源点v0到T中各顶点的最短路径长度;重复这一步骤,直到所有的顶点都加入到集合S中,算法就结束了。


算法实现:
在Dijkstra算法里,为了求源点v0到其他各顶点vi的最短路径及其长度,需要设置3个数组:
a) dist[n]:dist[i]表示当前找到的从源点v0到终点vi的最短路径的长度,初始时,dist[i]为Edge[v0][i],即邻接矩阵的第v0行。
b) S[n]:S[i]为0表示顶点vi还未加入到集合S中,S[i]为1表示vi已经加入到集合S中。初始时,S[v0]为1,其余为0,表示最初集合S中只有顶点v0。
c) path[n]:path[i]表示v0到vi的最短路径上顶点vi的前一个顶点序号。采用“倒向追踪”的方法,可以确定v0到顶点vi的最短路径上的每个顶点。


在Dijkstra算法里,重复做以下3步工作:

1)  在数组dist[n]里查找S[i] != 1,并且dist[i]最小的顶点u;
2)  将S[u]改为1,表示顶点u已经加入进来了;
3)  修改T集合中每个顶点vk的dist及path数组元素值:当S[k] != 1,且顶点u到顶点vk有边(Edge[u][k]<MAX),且dist[u] + Edge[u][k] < dist[k],则修改dist[k]为dist[u] + Edge[u][k],修改path[k]为u。

因此Dijkstra算法的递推公式(求源点v0到各顶点的最短路径)为:


eg:

      利用Dijkstra算法求下图中顶点0到其他各顶点的最短路径长度,并输出对应的最短路径。


       假设数据输入时采用如下的格式进行输入:首先输入顶点个数n,然后输入每条边的数据。每条边的数据格式为:u v w,分别表示这条边的起点、终点和边上的权值。顶点序号从0开始计起。最后一行为-1 -1 -1,表示输入数据的结束。


#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;

const int MAXN  = 20;
const int INF = 1000010;

int dist[MAXN];
int path[MAXN];
int S[MAXN];
int Edge[MAXN][MAXN];
int n;

void Dijkstra(int v0)
{
	int i, j;
	memset(dist, 0, sizeof(dist));
	for (i = 0; i < n; ++i)
	{
		dist[i] = Edge[v0][i];//初始时dist中存放v0所在的行
		S[i] = 0;
		if (i != v0 && dist[i] < INF)
			path[i] = v0;
		else
			path[i] = -1;
	}

	S[v0] = 1, dist[v0] = 0;//只有v0 在S中

	for (i = 0; i < n-1; ++i)
	{
		int MIN = INF, v = v0;
		for (j = 0; j < n; ++j)
		{
			if ( !S[j] && MIN > dist[j] )//在T中找具有最短路径的定点v
			{
				MIN  = dist[j];
				v = j;
			}
		}
		S[v] = 1;//表示v已经加入进来
		for (j = 0; j < n; ++j)//由于v的加入,可能会导致v0到T中顶点dist[]值“缩短”,如果dist的值修改自然也要修改path
		{
			if (!S[j] && Edge[v][j] < INF && (dist[v] + Edge[v][j] < dist[j]))
			{
				dist[j] = dist[v] + Edge[v][j];
				path[j] = v;
			}
		}
	}
}


int main()
{
	int i, j;
	int u, v, w;
	cin>>n;
	while (1)
	{
		cin>>u>>v>>w;
		if(u == -1 && v == -1 && w == -1)
			break;
		Edge[u][v] = w;
	}

	for (i = 0; i < n; ++i)
	{
		for (j = 0; j < n; ++j)
		{
			if(i == j)
				Edge[i][j] = 0;
			else if(Edge[i][j] == 0)
				Edge[i][j] = INF;
		}
	}

	Dijkstra( 0 );

	int shortest[MAXN];
	for (i = 1; i < n; ++i)
	{
		cout<<dist[i]<<"\t";
		memset(shortest, 0, sizeof(shortest));//找到从v0到i的最短路径上的点
		int k = 0;
		shortest[k] = i;
		while (path[ shortest[k] ] != 0)
		{
			k++;
			shortest[k] = path[ shortest[k-1] ];
		}
		k++;
		shortest[k] = 0;
		for(j = k; j > 0; --j)
			cout<<shortest[j]<<" -> ";
		cout<<shortest[0]<<endl;
	}
	return 0;
}

dijkstra与Prim算法有很大的相似性,Prim中lowcost存放的是T中各个顶点到S中各个顶点的权值最小值,而修改的时候,lowcost[k] = min{lowcost[k], Edge[v][k]}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值