最短路径问题——迪杰斯特拉算法(Dijkstra算法)

1.最短路径问题

     求从图中某一个点到另外一个点所经过的边权值加和最小的一条路径的权值和。

2.算法思路

     定义一个dis数组,储存图中所有点到原点的距离。

    在初始状态下,如果源点是1,那么dis[1]=0, dis[i]为原点到编号为i的点的边的权值,如果源点到i没有边,dis[i]=INF(初始化为无穷大)。

     如果要对dis[i]进行更新,即找到源点到i的较dis[i]更短的路径,必然经过其它点的中转。那么此时在dis数组中找到除i==1外最小的一个值,假如叫做dis[n],那么这个数已经不可能被更新(不存在点m使dis[m]+edge[m][n]<dis[n],因为此时dis[n]<=dis[m])。我们利用一个flag数组对它进行标记,即之后不再考虑这个点距离的更新(flag[n]=1)。之后我们以n为中转点,尝试更新源点到别的点的最短路径。遍历1到n,如果n到点i有边,flag[i]==0,我们考虑是否能以n为中转点更新源点到i的最短距离,即比较dis[i]和dis[n]+edge[n][i]的大小。在尝试更新完所有以n为中转点的可能之后,我们重新找在dis数组中flag为零的最小数,再次尝试更新,直到所有点的flag为1。

     (可以看大佬们做的示意图,有助于理解)

3.程序实现步骤

     a. edge和dis数组初始化为INF

     b. 找到dis数组中flag为0的最小值,并以其为中转点更新dis数组

     c. 重复b直到所有点的flag为1

下面附上本蒟蒻丑陋的代码:

#include <cstdio> 
#include <algorithm>
#define INF 0x3f3f3f3f
using namespace std;


int edge[1100][1100],dis[1100],flag[1100],query,n,m,x;


void Dijkstra()
{
	int low=INF,spr;//low代表当前找到的最小的flag为0的点的dis值 ,spr为点的编号 
	for(int i=1;i<=n;i++)
	{
		if(dis[i]<low&&flag[i]==0&&i!=x)
		{
			low=dis[i];
			spr=i;
		}
	}
	flag[spr]=1;
	for(int i=1;i<=n;i++)
	{
		if(edge[spr][i]+dis[spr]<dis[i])
		{
			dis[i]=edge[spr][i]+dis[spr];//更新dis数组 
		}
	} 
}


int main()
{
	int a,b,c;
	scanf("%d %d",&n,&m);//共有n个点,m条边 
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			edge[i][j]=INF;
		}
	}
	for(int i=1;i<=n;i++)
	{
		dis[i]=INF;
	}//初始化为INF 
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d %d",&a,&b,&c); 
		edge[a][b]=c,edge[b][a]=c;
	}
	scanf("%d %d",&x,&query);
	flag[x]=1,dis[x]=0;
	for(int i=1;i<=n;i++)
	{
		edge[i][i]=0;
		if(edge[x][i]!=INF) dis[i]=edge[x][i];
	}
	for(int i=1;i<n-1;i++)
	{
		Dijkstra();
	}
	printf("%d",dis[query]);
	/*
	for(int i=1;i<=n;i++)
	{
		printf("%d ",dis[i]);
	}
	*/
	return 0;
}

(如有错误请务必指正)

(我刚学的。。理解可能还不够深刻,轻喷)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值