迪杰斯特拉算法(解决单源最短路径问题)

        迪杰斯特拉算法用于解决图的单源最短路径问题,即给定a和b点,求a到b的最短路径。但是局限性在于不能处理图中含有负权边的情况。迪杰斯特拉算法和弗洛伊德算法非常类似,只不过是弗洛伊德是对所有结点对都做了松弛操作,而迪杰斯特拉算法只对给定的结点对做松弛,基本思路是很像的。这里就不解释松弛操作了,详见:弗洛伊德算法

基本思路:

        从给定的起点出发,找一个离它最近且没有访问的点,然后以找到的点为中转点做松弛操作。然后重复上述过程,最后得到起点到其他每个点的最短路径。之所以要选择最近的没有访问过的点是为了可以保存最短路径,其实只要和弗洛伊德一样,顺次遍历其他点就可以得到最短路径的路径和。

数据结构:

  • 图的邻接矩阵,用来保存图的信息
  • visit数组,用来判断一个点有没有被访问过
  • dst数组,用来储存起点到每个点的最短路径,在算法过程中是在动态更新的

算法过程:

  1. 从起点出发,找最近的一个没有访问过的点,即权值最小的边。
  2. 以找到的点为中转点,对没有访问过的点做进行一轮松弛操作。
  3. 重复1,直到所有点都遍历完。

例题:

        给你n个点,m条无向边,每条边都有长度d和花费p,给你起点s,终点t,要求输出起点到终点的最短距离及其花费,如果最短距离有多条路线,则输出花费最少的。输入n和m,再输入m个四元组,表示两个顶点间的距离和花费,再输入起点和终点。 

        由于这个题里的边还有花费这一属性,所以本题用结构体来保存边的长度和花费。还要一个spend数组,来储存起点到每个点的最短路径的花费。用上述迪杰斯特拉算法的思路来解。

c++代码:

#include<iostream>
#include<string.h>
#define inf 999999
#define max 105
using namespace std;
//由于一条边有两个信息,则用结构体来储存 
struct Edge
{
	int len;
	int cost;
};
Edge edge[max][max];
//dst表示起点到每个点的最短距离,spend表示起点到每个点的最短路径下的花费,visit为标记数组 
int m,n,dst[max],visit[max],spend[max];
int main()
{
	int i,j,start,end;
	cin>>n>>m;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			edge[i][j].cost=0;
			edge[i][j].len=inf;
		}
		edge[i][i].len=0;
	}
	while(m--)
	{
		cin>>i>>j;
		cin>>edge[i][j].len>>edge[i][j].cost;
		edge[j][i].cost=edge[i][j].cost;
		edge[j][i].len=edge[i][j].len;
	}
	cin>>start>>end;
	//对dst和spend初始化为从起点直接到另一个点的距离和花费 
	for(int i=1;i<=n;i++)
	{
		dst[i]=edge[start][i].len;
		spend[i]=edge[start][i].cost;
	}
	memset(visit,0,sizeof(visit));
	visit[start]=1;
	int k;
	for(k=1;k<n;k++)
	{
		//找到距离最近的点minnode。 
		int minnode,minlen=inf;
		for(int i=1;i<=n;i++)
		{
			if(visit[i]==0 && minlen>dst[i])
			{
				minlen=dst[i];
				minnode=i;
			}
		}
		//确定要走这个点了,标记为1 
		visit[minnode]=1;
		//对每个点进行松弛操作,因为本题中还要考虑花费,所以当两个路径距离相同时,比较一下花费 
		for(int i=1;i<=n;i++)
		{
			if(visit[i]==0 && dst[i]>(dst[minnode]+edge[minnode][i].len) || dst[i]==(dst[minnode]+edge[minnode][i].len) && spend[i]<spend[minnode]+edge[minnode][i].cost)
			{
				dst[i]=dst[minnode]+edge[minnode][i].len;
				spend[i]=spend[minnode]+edge[minnode][i].cost;
			}
		}
	}
	cout<<dst[end]<<" "<<spend[end];
	return 0;
}

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值