2021/05/29 单源带权图最短路径(Dijkstra算法)

如上图,假设我们要算从顶点0到其余顶点的最短路径,答案如下:

0——00(自己到自己)
0——113(0->1)
0——28(0->2)
0——313(0->2->3)
0——419(0->2->3->4)
0——521(0->2->3->4->5)
0——620(0->1->6)

 

该算法其实就是在无权图最短路径的算法基础上加了一点东西。它们的共同点是都需要一个记录路径长度数组dist[]和一个记录来时走过的路的数组path[];不同的是它多了一个收录的数组S[]

接下来在S未收录的顶点里面找到最小距离的那个顶点v;如果顶点v不存在了(所有点都已经收录并且没有再小的路径了)就表示已经完成了这个算法(找到了从源点i到其余点的所有最短路径了)

在做这些算法之前我们要初始化一些东西;

初始化S数组:将我们要算的某源点i收录进去(赋值为1),其余顶点不收录,(赋值为0)

初始化path[](全部弄成-1)

初始化dist[] :

1、源点dist[i]赋值为0(自己到自己的距离为0)

2、源点i到它触手可及的点 j 要赋值;

3、剩下的dist值全为正无穷;

    int j; 
	dist[i]=0;//从i到i的距离为0	
	S[i]=1;//收录i
	for(j=0;j<N;j++)
	{
		if(a[i][j]>0)
		dist[j]=a[i][j];//如果顶点i到j点有边,初始化j的路径 
        else
        dist[j]=MAX;//正无穷
	}

做完一系列初始化工作(有点繁琐)再来开始进行核心算法:

int findmin()//找到dist中未收录最小的值 
{
	int min=MAX,mini=-1,i;
	for(i=0;i<N;i++)
	{
		if(dist[i]<min&&S[i]==0)
		{
			min=dist[i];
			mini=i;
		}		
	}
	return mini;
}
while(1)//进入一个循环 
	{	
	     int v=findmin();//令v等于dist中未收录最小的值 
	     if(v==-1)//V不存在了,结束搜索 
		 break;
		 S[v]=1;//将v收录
		int w;
		for(w=0;w<N;w++)
		{
			if(a[v][w]>0&&S[w]==0)//如果V的邻接点W未收录 
			if(dist[v]+a[v][w]<dist[w])//如果点v到w距离比dist[w]小,更新它 
			{
				dist[w]=dist[v]+a[v][w];//更新路径长度 
				path[w]=v;//更新路径 					 
			}
		}
	}

 

完整测试代码:

#include<stdio.h>
#include<stdlib.h>
#define MAX 10000000 //正无穷 
int N;//顶点数 
int E;//边数 
int a[10][10];//邻接矩阵 
int dist[10];//更新路程 
int path[10];//更新路径 
int S[10];//记录已收录的点
int findmin();//找到dist中未收录最小的值 
void Dijkstra(int x);//x为从某点开始 
int main()
{
	int i,x1,x2,w;	
	for(i=0;i<110;i++)
	path[i]=-1;//初始化路径 
	scanf("%d%d",&N,&E);
	for(i=0;i<E;i++)
	{
		scanf("%d%d%d",&x1,&x2,&w);
		a[x1][x2]=w;//给每条路赋予权重 这里假设权重即路径(大于0) 
	}
	Dijkstra(0);//从顶点0找最短路径
	/*printf("从顶点0到其他顶点的路径分别为\n");
	for(i=0;i<N;i++)
	{
		printf("到顶点%d的路径长度:%d\n0",i,dist[i]);
		int t=i;
		int way[10],cnt=0;    	
	    while(path[t]!=-1)
	    {
	    	way[cnt++]=t;
	    	t=path[t];
		}
		while(cnt--)	printf("->%d",way[cnt]);					
		printf("\n");
	} */
	return 0;
}
int findmin()//找到dist中未收录最小的值 
{
	int min=MAX,mini=-1,i;
	for(i=0;i<N;i++)
	{
		if(dist[i]<min&&S[i]==0)
		{
			min=dist[i];
			mini=i;
		}		
	}
	return mini;
}
void Dijkstra(int x)
{	
	int i; 
	dist[x]=0;//从x到x的距离为0	
	S[x]=1;//收录x
	for(i=0;i<N;i++)
	{
		if(a[x][i]>0)
		{
		dist[i]=a[x][i];//如果顶点0到该点有边,初始化它们的路径 
		path[i]=x;
	    }
        else
        dist[i]=MAX;
	}
	//以上是初始化,以下为核心算法
	while(1)//进入一个循环 
	{	
	     int v=findmin();//令v等于dist中未收录最小的值 
	     if(v==-1)//V不存在了,结束搜索 
		 break;
		 S[v]=1;//将v收录
		int w;
		for(w=0;w<N;w++)
		{
			if(a[v][w]>0&&S[w]==0)//如果V的邻接点W未收录 
			if(dist[v]+a[v][w]<dist[w])//如果点v到w距离比dist[w]小,更新它 
			{
				dist[w]=dist[v]+a[v][w];//更新路径长度 
				path[w]=v;//更新路径 					 
			}
		}
	}
}

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值