阿空要找工作了系列之最短路径算法

本文深入探讨了最短路径算法,包括Dijkstra算法和Floyd算法的原理与实现。通过对比最小生成树,阐述了两种算法如何在图论中找到两点间的最短路径。提供了详细的代码示例,帮助读者理解算法的运作过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最短路径

1. 理解

  • 以前数学建模的时候涉及过一点图论的东西,那时候刚接触最短路径简直头大,现在倒是觉得简单很多,其思想与最小生成树很相似。
  • 最小生成树能够保证整个拓扑图的所有路径之和最小,最短路径是保证两点间路径最小,乍一看还是很相似,区别在于MST是全局最优,而最短路径是局部最优,但又不能这么说,因为MST针对的是所有点,而最短路径只针对两个点(其中涉及其他点的连接)。
  • 类比MST,常用算法是从点入手找边的Dijkstra和从边入手找点的Floyd。

2. Dijkstra

  • 主要原理上和prim算法的区别在于Dijkstra可能针对有向图,因此不同方向的边权可能不同。另一方面在于“最低权值”的定义不同,Prim的“最低权值”是相对于任意一点而言的,也就是把U中的点看成一个整体,每次寻找V-U中跟U的距离最小的一点加入U;而Dijkstra的“权值最低”是相对于出发点而言的,也就是每次寻找V-U中跟v0的距离最小的一点加入U。其实基本上是一样的,只是有细微的差别。
  • 代码
//这个函数只是为了方便显示路径,用来回溯路径的迭代方法
void fin(vector<int>* ppath, int index)
{
	vector<int> path = *ppath;
	if (path[index] == 0)
		cout << "V1->"<<"V"<<index+1;
	else if (path[index] == -1)
		cout <<"V1->V" <<index+1;
	else
	{		
		fin(ppath, path[index]);
		cout <<"->V" << index+1;		
	}
}
int main()
{
//赋值
	vector<vector<int>> weight = {		
		vector<int>{1,3,10},
		vector<int>{1,5,30},
		vector<int>{1,6,100},
		vector<int>{2,3,5},
		vector<int>{3,4,50},
		vector<int>{4,6,10},
		vector<int>{5,6,60},
		vector<int>{5,4,20},	
	};	
	int pointnum = 6;
	vector<vector<int>> graph(pointnum);
	for (int i = 0; i <pointnum; i++)
	{		
		vector<int> e(pointnum);
		for (int j = 0; j < pointnum; j++)
		{
			if (i == j)
				e[j] = 0;
			else
				e[j] = INT16_MAX;
		}
		graph[i] = e;
	}
	for (int k = 0; k < weight.size(); k++)
	{
		graph[weight[k][0]-1][weight[k][1]-1] = weight[k][2];		
	}
	//两点间最短路径长度
	vector<int> d(pointnum);	
	vector<int> v(pointnum);
	//距离索引点最近的下一个点索引号
	vector<int> p(pointnum,-1);
	for (int i = 1; i < pointnum; i++)
	{
		d[i] = INT16_MAX;
	}
	for (int i = 0; i < pointnum; i++)
	{
		int x;
		int m = INT16_MAX;
		for (int j = 0; j < pointnum; j++)
		{	
			if (v[j]==0 && d[j] <= m)
			{
				m = d[j];
				x = j;
			}
		}
		v[x] = 1;
		for (int j = 0; j < pointnum; j++)
		{
		
			if (d[x] + graph[x][j] < d[j])
			{
				d[j] = d[x] + graph[x][j];
				p[j] = x;
			}
		}
	}
	for (int i = 0; i < pointnum; i++)
	{
		fin(&p, i);
		cout << " 最短路径为" << d[i] << endl;		
	}
	return 0;
}

3. Floyd

  • 主要原理上…额,啥玩意儿,这东西也算个算法?不就是遍历对比所有路径长度么?不过输出路径的时候倒是觉得麻烦了许多。
  • 代码
vector<vector<int>> p;
void fin(int fr, int to)
{
	if (p[fr][to] == 0)
		cout << "V" << fr + 1 << "->V" << to + 1;
	else if (p[fr][to] == -1)
		cout << "V" << fr + 1 << "->V" << to + 1 ;
	else
	{
		fin(fr, p[fr][to]);
		cout << "->";
		fin(p[fr][to], to);
	}
}
int main()
{
	vector<vector<int>> weight = {		
		vector<int>{1,3,10},
		vector<int>{1,5,30},
		vector<int>{1,6,100},
		vector<int>{2,3,5},
		vector<int>{3,4,50},
		vector<int>{4,6,10},
		vector<int>{5,6,60},
		vector<int>{5,4,20},	
	};	
	int pointnum = 6;
	p.resize(pointnum);
	for (int i = 0; i < pointnum; i++)
	{
		vector<int> path(pointnum);
		for (int j = 0; j < pointnum; j++)
		{
			path[j] = -1;
		}
		p[i] = path;
	}
	vector<vector<int>> graph(pointnum);
	for (int i = 0; i <pointnum; i++)
	{		
		vector<int> e(pointnum);
		for (int j = 0; j < pointnum; j++)
		{
			if (i == j)
				e[j] = 0;
			else
				e[j] = INT16_MAX;
		}
		graph[i] = e;
	}
	for (int k = 0; k < weight.size(); k++)
	{
		graph[weight[k][0]-1][weight[k][1]-1] = weight[k][2];	
		p[weight[k][0] - 1][weight[k][1] - 1] = 0;
	}	
	for (int k = 0; k < pointnum; k++)
	{
		for (int i = 0; i < pointnum; i++)
		{
			for (int j = 0; j < pointnum; j++)
			{
				if (graph[i][j] > graph[i][k] + graph[k][j])
				{
					graph[i][j] = graph[i][k] + graph[k][j];				
					p[i][j] = k;
				}
			}
		}
	}
	//输出最终的结果
	for (int i = 0; i < pointnum; i++)
	{
		fin(0,i);
		cout << " 最短路径为" << graph[0][i] << endl;	
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值