再论最短路

上学期学习离散数学的时候当时做了些最短路的题,不过都很皮毛,这学期学数据结构刚好学到了,再次总结和整理一下。

首先复习一次dijkstra算法。

复杂度是n平方,用的是动态规划的思想,用一个数组L[i]来表示源点到i点的最短路径,我用map[i][j]表示从顶点i到顶点j的距离,然后将顶点划分成两部分,一部分是已经求出从源点到该点最短路径的点,一部分是还不知道最短路径的点,用P[i]为true来表示这个点还不知道最短路径是多少。然后外层循环依次选点,内层首先找到离这点最近且不知道源点到该点最短路的一点,然后再松弛该点即可。

理解算法成立的一个要点就是要理解到松弛是互不影响的,比如A点通过B点到D的最短路径是5,而通过C到D的最短路径是3.所以最后L[D]=3. 那么是不是必须按顺序松弛呢?这是没有必要的,比如你先算A到D的最短路径是3,而后遍历到B点开始松弛,发现路径为5,这时候是不会更改L[D]的,所以不用担心啦。


这次我的参考书是<<算法导论>>,里头首先介绍的是松弛技术.

所谓的松弛技术,是对一个点而言的,假设对顶点v,搜索所有可以到达v的点,我们用j来代表遍历到的v点可以到达的点。看看L[j]是否大于L[v]+map[v][j]如果成立则令L[j]=L[v]+map[v][j].根据那页底下的注释,这个名字的由来和三角不等式有关,满足此约束并没有“压力”,所以这个不等式约束是“松弛的”。

松弛前还要进行初始化。

我写的dijkstra代码如下

#include <iostream>
using namespace std;
#define MAXN 101
#define INF 0x3fffffff
int N,M,map[MAXN][MAXN],rounte[105];//rounte[i]=j表示i的前驱是j,也就是算法导论里头的那个π,所谓前驱就是从源点到i的最短路的i的前头那个点
void print(int endp,int startp)   //递归打印最短路径函数
{
	if(rounte[endp]!=startp)  //如果endp的前驱不是起始点的话,继续递归,现在打出路线的话路线是反的
		print(rounte[endp],startp);
	else cout<<startp<<" "; //这时候递归到起始点了,先把起始点打出来
	cout<<endp<<" ";  
}
int dijkstra(int source,int destination)
{
	int L[105];      //L[i]表示源点到i点的最短路径
	bool P[105];     //P[i]为true表示还不知道源点到i点的最短路
	for(int i=1;i<=N;++i)   //初始化,L[i]=无穷表示不可到达,即不存在最短路,
		L[i]=INF,P[i]=true,rounte[i]=i;
	L[source]=0;  //到本身的最短路为0

	for(int i=1;i<=N;++i)     //每个顶点遍历一次
	{
		int x,min=INF;
		for(int j=1;j<=N;++j)    //找到距离当前点最近的点x
		{
			if(P[j] && min>L[j])  
			{
				min=L[j];
				x=j;
			}
		}

		P[x]=false;
		for(int j=1;j<=N;++j)  //松弛该点x
		{
			if(map[x][j]!=INF && L[j]>L[x]+map[x][j])
			{
				L[j]=L[x]+map[x][j];
				rounte[j]=x;
			}
		}
	}
	print(destination,source);
	cout<<endl;
	return L[destination];  //返回源点到点destination的最短路
}
int main()
{
	while(cin>>N>>M && N && M) //N表示有N个顶点,M表示有M条路,且我假设是无向路
	{
		for(int i=1;i<=N;++i)
			for(int j=1;j<=N;++j)
				map[i][j]=INF;
		for(int i=1;i<=M;++i)
		{
			int source,destination,length;
			cin>>source>>destination>>length;
			map[source][destination]=map[destination][source]=length;
		}
		cout<<dijkstra(1,N)<<endl;
	}
	return 0;
}


后续在看看其他算法o(∩_∩)o





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值