【原创】求最短路径-dijkstra算法

有这样一类题,它要求你从某个点出发,到某个为止走过的最短路径。

上一次,我们学习了弗洛伊德算法,这次,我们来看看dijkstra算法。


从起点出发,有很多条路可以走,走哪一条路最短呢?

枚举出来看一看吧。依次枚举每条边。走最短的那一条路,最后到达终点时就一定最短啦!~\(≧▽≦)/~

但是这种做法有瑕疵:不能处理负权边,负权回路,O(n²)的代码只适合单源点,即只有出发点到目标点的距离,不像弗洛伊德可以处理任意两点的距离。

这种算法的时间复杂度为O(n²),改一改改成多源点就是O(n³)了。

详见代码:

//dis[i][j]:从i点到j点的距离,
//ans[i]:i点到源点的距离,
//bobo[i]:i点有没有走过
for(int i=1;i<=n;i++) ans[i]=dis[i][begin];
bobo[begin]=true; ans[begin]=0;//标记一下
for(int i=1;i<=n;i++)
{
	mini=VeryBig;
	int p=-1;//以此点出发,最短的路径的点的下表
	for(int j=1;j<=n;j++)
		if(!bobo[j] && ans[j]<mini)
			mini=ans[j],p=j;//若没有访问过且此点是最短路径,标记一下
	if(p<0) break;
	bobo[p]=true;//标记一下
	for(int j=1;j<=n;j++)
		ans[j]=min(dis[p][j]+ans[p],ans[j]);//尝试改变以此点出发的边的另一个端点的的值
}


我们还可以写出多源点的dijkstra算法。(应该可以吧,我没试过)

//dis[i][j]:从i点到j点的距离,
//ans[i][j]:i点到j点的最短距离,
//bobo[i]:i点有没有走过
for(int t=1;t<=n;t++)
{
	memset(bobo,0,sizeof bobo);
	for(int i=1;i<=n;i++) ans[t][i]=dis[i][begin];
	bobo[begin]=true; ans[t][begin]=0;//标记一下
	for(int i=1;i<=n;i++)
	{
		mini=VeryBig;
		int p=-1;//以此点出发,最短的路径的点的下表
		for(int j=1;j<=n;j++)
			if(!bobo[j] && ans[t][j]<mini)
				mini=ans[t][j],p=j;//若没有访问过且此点是最短路径,标记一下
		if(p<0) break;
		bobo[p]=true;//标记一下
		for(int j=1;j<=n;j++)
			ans[t][j]=min(dis[p][j]+ans[t][p],ans[t][j]);//尝试改变以此点出发的边的另一个端点的的值
	}
}

再来做一道例题吧!


题目描述


平面上有n个点(n<=100),每个点的坐标均在-10000~10000之间。其中的一些点之间有连线。若有连线,则表示可从一个点到达另一个点,即两点间有通路,通路的距离为两点间的直线距离。现在的任务是找出从一点到另一点之间的最短路径。

输入

第1行:1个整数n
第2..n+1行:每行2个整数x和y,描述了一个点的坐标
第n+2行:1个整数m,表示图中连线的数量
接下来有m行,每行2个整数i和j,表示第i个点和第j个点之间有连线

最后1行:2个整数s和t,分别表示源点和目标点

输出

第1行:1个浮点数,表示从s到t的最短路径长度,保留2位小数

样例输入

5
0 0
2 0
2 2
0 2
3 1
5
1 2
1 3
1 4
2 5
3 5
1 5

样例输出

3.41

详见代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#include<cstdlib>
#include<queue>
#include<stack>
#include<map>  
#include<vector>  
#include<functional>  
using namespace std;
const int VeryBig=9999999;
struct Epic
{
	int x,y;
}point[111];
double dis[111][111],ans[111];
int n,m,begin,end,a,b,bobo[111],mini;
void in()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++) scanf("%d %d",&point[i].x,&point[i].y);
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			dis[i][j]=ans[i]=VeryBig;
	scanf("%d",&m);
	for(int i=1;i<=m;i++)
	{
		scanf("%d %d",&a,&b);
		dis[a][b]=dis[b][a]=sqrt(double((point[a].x-point[b].x)*(point[a].x-point[b].x)+(point[a].y-point[b].y)*(point[a].y-point[b].y)));
	}
	scanf("%d %d",&begin,&end);
}
void search()
{
	for(int i=1;i<=n;i++) ans[i]=dis[i][begin];
	bobo[begin]=true; ans[begin]=1;
	for(int i=1;i<=n;i++)
	{
		mini=VeryBig;
		int p=-1;
		for(int j=1;j<=n;j++)
			if(!bobo[j] && ans[j]<mini)
				mini=ans[j],p=j;
		if(p<0) break;
		bobo[p]=true;
		for(int j=1;j<=n;j++)
			ans[j]=min(dis[p][j]+ans[p],ans[j]);
	}
}
int main()
{
	/*freopen("dijkstra.in","r",stdin);
	freopen("dijkstra.out","w",stdout);*/
	in();
	search();
	printf("%.2lf",ans[end]);
	return 0;
} 



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进课程实践、课外项目或毕业设计。通过分析和运源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值