Fork me on GitHub

Dijkstra算法

定义
\( Dijkstra算法一般的表述通常有两种方式,一种用永久和临时标号方式,一种是用OPEN, CLOSE表的方式,这里均采用永久和临时标号的方式。注意该算法要求图中不存在负权边。 \)
原理
\( 1.首先,引入一个辅助数组(vector)D,它的每个元素D[i]表示当前所找到的从起始点(即源点v)到其它每个顶点v_i的长度。 \\ 例如,D[3]=2表示从起始点到顶点3的路径相对最小长度为2。这里强调相对就是说在算法执行过程中D的值是在不断逼近最终结果但在过程中不一定就等于长度。 \\ 2.D的初始状态为:若从v到v_i有弧(即从v到v_i存在连接边),则D 为弧上的权值(即为从v到v_i的边的权值);否则置D[i]为∞。 \\ 显然,长度为D[j]=Min\{D|v_i∈V\}的路径就是从v出发到顶点v_j的长度最短的一条路径,此路径为(v,v_j)。 \\ 3.那么,下一条长度次短的是哪一条呢?也就是找到从源点 到下一个顶点的最短路径长度所对应的顶点,且这条最短路径长度仅次于从源点v到顶点v_j的最短路径长度。 \\ 假设该次短路径的终点是v_k,则可想而知,这条路径要么是(v,v_k),或者是(v,v_j,v_k)。它的长度或者是从v到v_k的弧上的权值,或者是D[j]加上从v_j到v_k的弧上的权值。 \\ 4.一般情况下,假设S为已求得的从源点v出发的最短路径长度的顶点的集合,则可证明:下一条次最短路径(设其终点为x)要么是弧(v,x),或者是从源点 出发的中间只经过S中的顶点而最后到达顶点x的路径。 \\ 因此,下一条长度次短的的最短路径长度必是D[j]=Min\{D[i]|∈V-S\},其中D 要么是弧( )上的权值,要么是D[k](v_k∈S)和弧(v_k,v_i)上的权值之和。 \\ 算法描述如下: \\ 1)令arcs表示弧上的权值。若弧不存在,则置arcs为∞(在本程序中为MAXCOST)。S为已找到的从v出发的的终点的集合,初始状态为空集。那么,从v出发到图上其余各顶点v_i可能达到的长度的初值为D=arcs[Locate\ Vex(G,v_i )],v_i∈V; \\ 2)选择v_j,使得D[j]=Min\{D|v_i∈V-S\}; \\ 3)修改从v出发的到集合V-S中任一顶点v_k的最短路径长度。 \)
问题描述
\( 在有向图G=(V,E)中,假设每条边E[i]的长度为w[i],找到由顶点V_0到其余各点的最短值。 \)
算法思想
\( 按路径长度递增次序产生算法: \\ 把顶点集合V分成两组: \\ (1)S:已求出的顶点的集合(初始时只含有源点V0) \\ (2)V-S=T:尚未确定的顶点集合 \\ 将T中顶点按递增的次序加入到S中,保证: \\ (1)从源点V_0到S中其他各顶点的长度都不大于从V_0到T中任何顶点的最短路径长度 \\ (2)每个顶点对应一个距离值 \\ S中顶点:从V_0到此顶点的长度 \\ T中顶点:从V_0到此顶点的只包括S中顶点作中间顶点的最短路径长度 \\ 依据:可以证明V_0到T中顶点V_k的,或是从V_0到V_k的直接路径的权值;或是从V_0经S中顶点到V_k的路径权值之和。 \\ (反证法可证) \\ 求最短路径步骤 \\ 算法步骤如下: \\ G=\{V,E\} \\ 1初始时令S=\{V_0\},T=V-S=\{其余顶点\},T中顶点对应的距离值 \\ 若存在(V_0,V_i),d(V_0,V_i)为(V_0,V_i)弧上的权值 \\ 若不存在(V_0,V_i),d(V_0,V_i)为\infty \\ 2从T中选取一个与S中顶点有关联边且权值最小的顶点W,加入到S中 \\ 3对其余T中顶点的距离值进行修改:若加进W作中间顶点,从V_0到V_i的距离值缩短,则修改此距离值 \\ 重复上述步骤2、3,直到S中包含所有顶点,即W=V_i为止 \)
代码

#include<iostream>
#include<climits>
#include<cstdlib>
#define MAXN 10001
using namespace std;
int a[MAXN][MAXN]={0},b[MAXN];
bool s[MAXN]={0};
int main(){
	ios::sync_with_stdio(false);
	int n,m;
	cout<<"点数&边数"<<endl;
	cin>>n>>m;
	for(int i=1;i<=m;i++){
		int x,y,z;
		cin>>x>>y>>z;
		a[x][y]=z;
		a[y][x]=z;
	}
	b[1]=0;
	for(int i=2;i<=n;i++)b[i]=INT_MAX;
	for(int i=1;i<=n;i++){
		int minn=INT_MAX,x;
		for(int j=1;j<=n;j++)
			if(!s[j]&&b[j]<minn)
			{
				minn=b[j];
				x=j;
			}
		s[x]=1;
		for(int j=1;j<=n;j++)if(a[x][j]&&!s[j]&&b[j]>b[x]+a[x][j])b[j]=b[x]+a[x][j];
	}
	for(int i=1;i<n;i++)cout<<b[i]<<"->";
	cout<<b[n]<<endl;
	return 0;
}
posted @ 2020-09-26 20:53  liusu123456  阅读(122)  评论(0编辑  收藏  举报