旅游规划pta(无向图求顶点间最短路径)

这篇博客介绍了求解图中最短路径的两种常见算法——Dijkstra算法和Floyd算法。Dijkstra算法用于求解从特定源点到其他顶点的最短路径,而Floyd算法则能找出图中任意两点间的最短路径。作者通过一个旅游规划的实例展示了如何应用这两种算法,并给出了相应的AC代码。Dijkstra和Floyd算法在解决这类问题时各有优势,可以根据实际需求选择使用。
摘要由CSDN通过智能技术生成

关于求图的顶点间最短路径问题,基本分为两种算法:

  1. Dijkstra算法
  2. Floyd算法

Dijkstra算法是用来求图中某个源点到其他顶点的最短路径的,而Floyd是用来求图中任意两个顶点间的最短路径。原理上Floyd可以对Dijkstra算法遍历以便所有顶点得到,但是Flody的写法更简单一点。
下面以一道经典例题为例
题目来源:PTA
旅游规划
有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:
输入说明:输入数据的第1行给出4个正整数N、M、S、D,其中N(2≤N≤500)是城市的个数,顺便假设城市的编号为0~(N−1);M是高速公路的条数;S是出发地的城市编号;D是目的地的城市编号。随后的M行中,每行给出一条高速公路的信息,分别是:城市1、城市2、高速公路长度、收费额,中间用空格分开,数字均为整数且不超过500。输入保证解的存在。

输出格式:
在一行里输出路径的长度和收费总额,数字间以空格分隔,输出结尾不能有多余空格。

输入样例:

4 5 0 3
0 1 1 20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20

输出样例:

3 40

附上利用Dijkstra算法的代码(分析可见代码注释)(AC源码)

#include <iostream>
#include <cstring>
using namespace std;

const int N = 510;
int dist[N][N];//两个城市间的距离 
int fee[N][N];	//城市间高速收费 
bool st[N];		//存储某个城市的最短路是否已经遍历过 
int n,m,s,d;	//n为城市数,m为路径数,s为起点,d为终点

void Dijstra(int s,int b)		//s为起点城市,b为终点城市 
{
	
	dist[s][s] = 0;				//初始化 
	
	for(int i = 0; i < n; i ++)//一共遍历n次
	{
		int t = -1;
		for(int j = 0; j < n; j ++)
		{
			if(!st[j] && (t == -1 || dist[s][t] > dist[s][j]))
			{
				t = j;//调用一个没有调用过的中间顶点
			}
		}
		
		st[t] = true;//某点被用过则标记以下
		
		for(int j = 0; j < n; j ++)//遍历所有点
		{
			if(dist[s][j] > dist[s][t] + dist[t][j]) //源点s通过t到达j 比 s直接到j 更短
			{
				dist[s][j] = dist[s][t] + dist[t][j]; //更新s到j的最短路径
				fee[s][j] = fee[s][t] + fee[t][j]; //更新收费额
			}
			else if(dist[s][j] == dist[s][t] + dist[t][j])
				fee[s][j] = min(fee[s][j], fee[s][t] + fee[t][j]);//路径相等时取收费最小的
			else continue;
		} 
	}
	
	cout << dist[s][b] << ' ' << fee[s][b];
	
}

int main()
{
	cin >> n >> m >> s >> d;
	
	memset(dist, 0x3f, sizeof dist);//初始化dist数组为inf 
	
	for(int i = 0; i < m; i ++)
	{
		int a,b,len,fe;
		cin >> a >> b >> len >> fe;
		if(dist[a][b] > len) //若两个城市间不止一条路径 
		{
            dist[a][b] = dist[b][a] = len;//无向图~~
            fee[a][b] = fee[b][a] =fe; 
        }
        else if(dist[a][b] == len) fee[a][b] = fee[b][a] = min(fee[a][b], fe);//路径相同时,收费取最小的 
	}
	
	Dijstra(s,d);
	
	return 0;
}

将Dijkstra算法换成Floyd算法也能AC

void Floyd(int s,int b)		//s为起点城市,b为终点城市 
{

	for(int t = 0; t < n; t ++)//t为path路径上的点
    {
        for(int i = 0; i < n; i ++)//i为起点
        {
		    for(int j = 0; j < n; j ++)//j为终点
		    {
			    if(i != j &&dist[i][j] > dist[i][t] + dist[t][j])//i通过t到达j 比 i直接到j 更短
			    {
				    dist[i][j] = dist[j][i] = dist[i][t] + dist[t][j];//由于是无向图,两个方向都要更新
				    fee[i][j] = fee[j][i] = fee[i][t] + fee[t][j];
			    }
			    else if(dist[i][j] == dist[i][t] + dist[t][j])
                    fee[i][j] = min(fee[i][j], fee[i][t] + fee[t][j]);//路径相同取收费最小
			    else continue;
		    } 
	    }
    }
	
	cout << dist[s][b] << ' ' << fee[s][b];
}

再单拎出Dijkstra算法

void Dijstra(int s,int b)		//s为起点城市,b为终点城市 
{
	
	dist[s][s] = 0;				//初始化 
	
	for(int i = 0; i < n; i ++)//一共遍历n次
	{
		int t = -1;
		for(int j = 0; j < n; j ++)
		{
			if(!st[j] && (t == -1 || dist[s][t] > dist[s][j]))
			{
				t = j;//调用一个没有调用过的中间顶点
			}
		}
		
		st[t] = true;//某点被用过则标记以下
		
		for(int j = 0; j < n; j ++)//遍历所有点
		{
			if(dist[s][j] > dist[s][t] + dist[t][j]) //源点s通过t到达j 比 s直接到j 更短
			{
				dist[s][j] = dist[s][t] + dist[t][j]; //更新s到j的最短路径
				fee[s][j] = fee[s][t] + fee[t][j]; //更新收费额
			}
			else if(dist[s][j] == dist[s][t] + dist[t][j])
				fee[s][j] = min(fee[s][j], fee[s][t] + fee[t][j]);//路径相等时取收费最小的
			else continue;
		} 
	}
	
	cout << dist[s][b] << ' ' << fee[s][b];
	
}

可以作一个对比观察。
如果还要求路径经过的城市,可以多增加一个path邻接矩阵来存储。
另外,这两个算法可以作为一个代码模板,类似的题基本可以一个模板过。

  • 1
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
在Java中,PTA(Priority-Driven A*)算法是一种启发式搜索算法,用于寻找从起点到终点的最短路径。它结合了Dijkstra算法和A*算法的特点,其中Dijkstra用于解决无权图的问题,而A*则使用了一个估价函数来优先探索更接近目标节点的路径。 以下是PTA Java中最短路径的基本步骤: 1. 初始化:创建一个开放列表(Open List),一个关闭列表(Closed List),起点为初始状态,终点为终止状态。设置起点的f值(f = g + h)为0,其中g值为实际代价,h值为启发式代价(通常是曼哈顿距离或欧几里得距离)。 2. 建立数据结构:通常使用优先队列(如PriorityQueue)来存储节点,按照f值排序。 3. 查找路径:循环直到开放列表为空或找到终点: a. 从优先队列中取出f值最小的节点(当前节点)。 b. 如果当前节点是终点,则回溯构建路径。 c. 否则,对于当前节点的所有邻居,检查它们是否在关闭列表中,如果不在,则加入开放列表,并更新它们的g值、f值和父节点引用。 4. 更新状态:将当前节点标记为已访问并添加到关闭列表。然后计算每个邻居的g值(从起点到该节点的实际代价加上从当前节点到邻居的代价)和f值(g值加上从起点到终点的启发式估计),根据这些值调整优先级。 5. 如果没有找到路径:说明从起点到终点可能不存在路径,或者图中存在负权边,导致传统Dijkstra算法失效。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AC Maker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值