旅游规划

旅游规划


一、目的

-掌握dijkstra算法
-掌握bool的用法


二、实验内容与设计思想

旅游规划

有了一张自驾旅游路线图,你会知道城市间的高速公路长度、以及该公路要收取的过路费。现在需要你写一个程序,帮助前来咨询的游客找一条出发地和目的地之间的最短路径。如果有若干条路径都是最短的,那么需要输出最便宜的一条路径。

输入格式:
输入说明:输入数据的第 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


题目分析:

代码重点在于最短路径的寻找


函数相关伪代码

1.const int INF = 0x3f3f3f3f;
2.struct path {
	int a;//路径
	int b;//花费
};
3.dijkstra算法 
c[s] = 0;
b[s] = 0;
for (int i = 0; i < n; i++) 
|int x = INF, y = -1;
|for (int j = 0; j < n; j++) 
||if (!vis[j] && c[j] < x) 
|||y = j;
|||x = c[j];
|end
|vis[y] = true;
|if (y == d)
||break;
|for (int k = 0; k < n; k++) 
||if (!vis[k] && a[y][k].a+ c[y] < c[k]) 
|||c[k] = c[y] + a[y][k].a;
|||b[k] = b[y] + a[y][k].b;
||else if (!vis[k] && a[y][k].a + c[y] == c[k]) 
|||if (a[y][k].b + b[y] < b[k]) 
||||b[k] = a[y][k].b + b[y];
end
|cout << c[d] << " " << b[d] << endl;
4.主函数
cin >> n >> m >> s >> d;
for (i = 0; i < m; i++) 
|cin >> x >> y >> z >> c;
|a[x][y].a = z;
|a[y][x].a = z;
|a[y][x].b = c;
|a[x][y].b = c;
end
for (i = 0;i < n;i++) 
|a[i][i].a = 0;
|a[i][i].b = 0;
end
dijkstra(n, m, s, d, a);


函数代码

#include <iostream>
#include <vector>
using namespace std;
const int INF = 0x3f3f3f3f;
struct path {
	int a;//路径
	int b;//花费
};
void dijkstra(int n, int m, int s, int d, vector<vector<path>>& a) {
	vector<int> b(n, INF);//花费
	vector<int> c(n, INF);//路径长
	vector<bool> vis(n, false);//是否访问过
	c[s] = 0;
	b[s] = 0;
	for (int i = 0; i < n; i++) {
		int x = INF, y = -1;
		for (int j = 0; j < n; j++) {
			if (!vis[j] && c[j] < x) {
				y = j;
				x = c[j];
			}
		}
			vis[y] = true;
			if (y == d)
				break;
			for (int k = 0; k < n; k++) {
				if (!vis[k] && a[y][k].a+ c[y] < c[k]) {
					c[k] = c[y] + a[y][k].a;
					b[k] = b[y] + a[y][k].b;
				}
				else if (!vis[k] && a[y][k].a + c[y] == c[k]) {
					if (a[y][k].b + b[y] < b[k]) {
						b[k] = a[y][k].b + b[y];
					}
				}
			}
		}
	cout << c[d] << " " << b[d] << endl;
	return;
}
int main() {
	int n, m, s, d, i, x, y, z, c;
	cin >> n >> m >> s >> d;
	vector<vector<path>>a(n, vector<path>(n, { INF,INF }));
	for (i = 0; i < m; i++) {
		cin >> x >> y >> z >> c;
		a[x][y].a = z;
		a[y][x].a = z;
		a[y][x].b = c;
		a[x][y].b = c;
	}
	for (i = 0;i < n;i++) {
	    a[i][i].a = 0;
	    a[i][i].b = 0;
	}
	dijkstra(n, m, s, d, a);
	return 0;
}

三、实验使用环境

以下请根据实际情况编写

  • 操作系统:Windows 11专业版
  • 编程语言:C++
  • 开发工具:[Visual Stdio 2022]

四、实验步骤和调试过程

旅游规划

本机运行截图

运行分析

第一行输入表示多少个点和路径数,求的起点和终点,可以根据点数来定义矩阵,之后输入路径数,输入一行有四个数,第一和第二个点表示两点之间联通,第三个点表示路径长,第四个表示花费,这些值一一对应,所以我们需要定义结构来存储第三个和第四个值,第一和第二可以作为坐标(以矩阵方式存储)。
输出的第一个数表示总路径长度(最短路径),用空格隔开,第二个数表示最少花费。


五、实验小结

遇到的问题及解决方法:

  1. 问题:dijkstra函数逻辑有问题
  • 解决方法:修改代码

实验体会和收获:

这段代码主要使用Dijkstra算法,用于解决在图(矩阵)中寻找从源点到目标点的最短路径,同时考虑路径长度和花费的问题。
首先要自定义一个结构,之后在主函数中,代码首先读取图的顶点数、边数、源点和目标点,然后初始化图的邻接矩阵(定义类型要为自定义类型),并读取每条边的路径长度和花费。最后,调用Dijkstra函数计算并输出从源点到目标点的最短路径长度和总花费。
Dijkstra算法的主要步骤包括:
1.vector初始化:定义三个数组c,b和vis来实现的,其中c数组存储从源点到每个顶点的最短路径长度,而b数组存储相应的总花费,vis表示结点是否已访问。设置源点的路径长度和花费为0,其他顶点的路径长度和花费为无穷大(需要自己定义一个较大的值,最好为0x7fffffff或2^31-1,这是int型除第一位(符号位)外,其它全为1的十六进制和十进制)。
进入循环,循环次数最多为顶点个数。
2.选择当前已访问结点到未访问结点的路径长度最短的顶点,用vis数组(bool型即可,初始化为全为false)来表示其已标记为已访问(将对应顶点数的值改为true)。
3.更新与该顶点相邻的顶点的路径长度和花费。如果新路径长度更短,则更新路径长度和花费;如果路径长度相同但花费更少,则只更新花费(因为每次一加一个点都要判断一遍,所以就不需要担心其它已访问节点到未访问节点的路径更短这一问题,在数组中的值绝对是目前到该结点最短的)。
4.重复上述过程,直到目标顶点被访问(大家可能认为还要判断所有顶点都访问的情况,但实际上已经被加入目标顶点被访问这一情况),提早退出循环。
5.输出目标顶点的路径长度和总花费(我用数组存的该顶点对应的值是到该结点总的最短花销,直接输出该数组对应的值就可以)。
因为这道题的编号是从0开始,就可以直接对应矩阵,但如果题目给的顶点是字符或字符串,那么就可以使用map来表示之间的映射关系,之后就是一样的思路。


posted @ 2025-05-13 21:41  穗和  阅读(10)  评论(0)    收藏  举报