旅游规划问题 composed by:yhl

目录

实验目的及内容

解题思路

实验代码及注释

输入输出说明及结果截图

心得体会

实验目的及内容

根据一张旅游路线图,已知城市之间的路线长度以及花费的费用。请编写程序输出一条从出发地到目的地之间的最短规划路线。如果存在若干条最短路径,则输出费用最少的一条路线。

解题思路

1.分析需求:

首先,大体上这是一个求单源最短路径问题,因而我打算基于迪杰斯特拉算法来求解,正好也可以复习一下课堂学习知识;

但是,题目还有进一步要求:(1).不仅要比较路径,同时要比较过路费;(2)还需要记录最短路径的具体“路线”,即这条路是怎么走的;

思考:

(1)倒是好解决,我们其实只需要照葫芦画瓢,把迪杰斯特拉算法稍作改动,加入比较过路费的操作即可,只是写代码的时候要注意,路径的优先级要高于路费

(2)要记录路径,其实只需对迪杰斯特拉算法足够熟悉,就能想到办法——记录每个节点的前驱,然后再逐级递归,直至出发点即可打印出完整的路径;如何完成对前驱的记录呢?

可以借助一个int path[]数组,其下标代表每个顶点的编号,其值存储前驱的编号;

首先,我们将与源点有通路的顶点前驱初始化为源点,没有通路的那些点,前驱初始化为无穷;

选择当前距离最少的点Ci加入源点所在S集合之后,我们需要更新各个顶点到S集合的最小距离,此时,重点来了,如果发现S集合外有一个点Bi的最短距离因为Ci的加入而变得更短了,那么就要把Ci设为其前驱;

因为如果这个Bi被加入了S集合,那么一定是通过Ci点与S集合进行连接的;所以,利用递推思想可以发现,只要每次“更新最短距离”的时候,也同时更新各个点的前驱,就可以记录路径了;

2.核心算法:迪杰斯特拉算法

实验代码及注释

#include <iostream>
#define Max 503
#define INF 0xcffffff//宏定义路程极大值
using namespace std;

int source;      //出发地编号
int destination;//目的地编号

//定义道路类
class road
{
	public:
		int distance;
		int cost;
};

//定义地图类
typedef class AMGraph
{
	public:
		int vex, arc;		//顶点数和边数
		road arcs[Max][Max];//邻接矩阵
};

int dis[Max];//dis保存source到其他各个点的最短路径总长
int path[Max];//path通过保存每个点的前驱结点来记录路径
bool book[Max];	//标记起点到某个点是否已找到最短路
int totalcost[Max];//保存路径的总路费

//改造版迪杰斯特拉算法
void Dijkstra(AMGraph &G,int start)
{
	//整体初始化工作
	for (int i = 1; i <= G.vex; i++)
		{
			dis[i] = G.arcs[start][i].distance;
			path[i] = dis[i] < INF ? 1 : -666;
			book[i] = false;
			totalcost[i]=G.arcs[start][i].cost;
		}
	//起点初始化
	book[start] = true;
	dis[start] = 0;//起点和起点间距离为0
	totalcost[start]=0;//呆在原地不用花钱

	//寻找start和其他各个点间的最小路径,大循环vex-1次
	for (register int i = 2; i <= G.vex; i++)
		{
			int mincost = INF;     //记录最少路费
			int mindistance = INF;//记录最短路长
			int u=start;//记录每次加入book集合的点

			//按照距离和路费两个指标,查找当前的最优点,加入book集合
			for (register int j = 1; j <= G.vex; j++)
				{
					if(!book[j])
						{
							//先寻找当前哪个点距离start最近
							if (mindistance > dis[j])
								{
									mindistance = dis[j];
									u = j;
									mincost= totalcost[j];
								}
							//如若距离相同,则找路费更少的那个点
							else if(mindistance==dis[j] && mincost > totalcost[j])
								{
									mincost = totalcost[j];
									u=j;
								}

						}

				}
			book[u] = true;//将最优点加入book集合

//加入后,再次遍历所有book外面的点,更新start到它们的最短路程长和路费
for ( int j = 1; j <= G.vex; j++)
{
	if(!book[j])
	{
		if (dis[j] > dis[u] + G.arcs[u][j].distance)
		{
				dis[j] = dis[u] + G.arcs[u][j].distance; 	  //更新最短路径值
				totalcost[j]= totalcost[u]+G.arcs[u][j].cost;//更新最短路径的路费
				path[j] = u;//修改j的前驱为u
								}
		//如若距离相同,则选择路费更少的那一条路

		else if (dis[j] == dis[u]+G.arcs[u][j].distance && totalcost[j] > totalcost[u] + G.arcs[u][j].cost)
								{
									totalcost[j]= totalcost[u]+G.arcs[u][j].cost;//更新最短路径的路费
									path[j] = u;//修改j的前驱为u
								}
						}

				}
		}
	return;
}
//递归输出最短路径
void findroad(int x)
{
	if (path[x] == source)
		{
			cout << "C"<<source;
		}
	else
		{
			findroad(path[x]);
		}
	cout << " -> C" << x;
	return;
}
//提示用户输入,并创建图
void input(AMGraph &G)
{
	cout<<"请输入所有城市的数量,以及道路总数:"<<endl;
	cin >> G.vex >> G.arc;
	cout<<"-----------------\n";
	//初始化邻接矩阵,register int 使用CPU内部寄存器,加快速度
	for (register int i = 1; i <= G.vex; i++)
		{
			for (register int j = 1; j <= G.vex; j++)
				{
					G.arcs[i][j].distance = INF;
					G.arcs[i][j].cost=INF;

				}

		}
	cout<<"输入每一条道路的信息:"<<endl;
	for (register int i = 1; i <= G.arc; i++)
		{
			int u, v, w,x;
			cout<<"其中一个城市是C";
			cin >> u ;
			cout<<"另外一个城市是C";
			cin>> v;
			cout<<"其间路长&路费:";
			cin>>w>>x;
			//无向图邻接矩阵必对称!
			G.arcs[u][v].distance = w;
			G.arcs[v][u].distance = w;
			G.arcs[u][v].cost=x;
			G.arcs[v][u].cost=x;
			cout<<"-----------------\n";
		}
	cout<<"请输入出发地C";
	cin>>source;
	cout<<"请输入目的地C";
	cin>>destination;
}
//输出
void output(AMGraph &G,int dest)
{
	cout<<"********************************************************\n";
	cout << "起点 C"<<source<<"到目的地C"<<dest<<"的最短路程长度为:";
	cout << dis[dest] ;
	cout<<",最少路费为:"<<totalcost[dest]<<endl;
	cout << "起点 C"<<source<<"到目的地C" << dest << "的具体路线: ";
	findroad(dest);
	cout << endl;
}
int main()
{
	AMGraph G;
	input(G);
	Dijkstra(G,source);
	output(G,destination);
	return 0;
}

输入输出说明及结果截图

输入:按照提示输入,本次测试样例基本上包含了各种可能情况,从C1到C2有两条长度相同的最短路径,并且在一开始C1到C3和C4距离都是最短的,因此验证了代码的健壮性

输出:输出题目要求的路线

心得体会

本次实验在迪杰斯特拉算法的基础上进行了一些拓展,加深了我对这个算法的理解,也让我对递归的写法更加熟练了。这次实验也充分告诉我,在写算法代码之前,在纸上把算法图示画一遍,对于代码的设计与实现是很有好处的!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值