算法笔记---【PAT A1030】Travel Plan

题目链接:【PAT A1030】Travel Plan

题目描述

A traveler’s map gives the distances between cities along the highways, together with the cost of each highway. Now you are supposed to write a program to help a traveler to decide the shortest path between his/her starting city and the destination. If such a shortest path is not unique, you are supposed to output the one with the minimum cost, which is guaranteed to be unique.

Input Specification:

Each input file contains one test case. Each case starts with a line containing 4 positive integers N, M, S, and D, where N (≤500) is the number of cities (and hence the cities are numbered from 0 to N−1); M is the number of highways; S and D are the starting and the destination cities, respectively. Then M lines follow, each provides the information of a highway, in the format:

City1 City2 Distance Cost

where the numbers are all integers no more than 500, and are separated by a space.

Output Specification:

For each test case, print in one line the cities along the shortest path from the starting point to the destination, followed by the total distance and the total cost of the path. The numbers must be separated by a space and there must be no extra space at the end of output.

样例:

输入:
4 5 0 3 //4个结点,5条边,起始点为0,终止点为3
0 1 1 20//结点0 到结点1 的边权为1 花费为20
1 3 2 30
0 3 4 10
0 2 2 20
2 3 1 20
输出:
0 2 3 3 40//输出起点到终点的最短路径0-2-3,最短路径的值为3,最少花费为40

题目大意:

有N个城市(编号为0~N-1)、M条道路(无向边),并给出M条道路的距离属性与花费属性。现在给定起点S与终点D,求从起点到终点的最短路径、最短距离及花费。
注意:
如果有多条最短路径,则选择花费最小的那条

解题思路:
1、使用Dijkstra算法求出最短路径和最短路径上的各个结点的父结点
2、使用DFS来求解第二个条件,即在距离最短的情况下,选出花费最少的路径
若该题代码不是很懂,建议查看 算法笔记—【PAT A1003 】Emergency
这两道题思想都相同,基本代码也大致相同,唯一的区别是该题的第二个条件是类似边权的最优,而 算法笔记—【PAT A1003 】Emergency 则是点权的最优解。

下面为AC代码:

#include <iostream>
#include <vector>
#include <limits.h>
#include <queue>
#include <map>
#include <algorithm>
using namespace std;

const int city_max_num = 501;
struct CityNode
{
	int id;		//当前结点的编号
	int weight; //边权
};

vector<int> path, temp_path;
int min_money = INT_MAX;
int money[city_max_num][city_max_num]; //表示各个边对应的花费
vector<int> parent[city_max_num];

struct MinWeightCompare
{
	bool operator()(const CityNode node1, const CityNode node2) const
	{
		return node1.weight > node2.weight;
	}
};

//************************************
// Method:    dijkstra 返回单源最短路径
// FullName:  dijkstra
// Access:    public
// Returns:   void
// Qualifier:
// Parameter: vector<DijNode> matrix[] 给定的图
// Parameter: DijNode start 初始结点
// Parameter: bool * visited 表示当前结点是否被访问
// Parameter: vector<int> parent[] 表示当前到结点的上一个结点
// Parameter: map<int,int> & distance 表示初始结点到当前结点的最短路径
//************************************
void dijkstra(vector<CityNode> matrix[], CityNode start, bool *visited, vector<int> parent[], map<int, int> &distance)
{

	priority_queue<CityNode, vector<CityNode>, MinWeightCompare> p_queue; //BFS 队列
	//该优先队列中的元素表示到当前结点的最短路径。
	p_queue.push(start);

	while (!p_queue.empty())
	{
		CityNode top_node = p_queue.top();
		p_queue.pop();
		visited[top_node.id] = true; //标记当前结点已被访问
		for (int i = 0; i < matrix[top_node.id].size(); i++)
		{
			CityNode next_node = matrix[top_node.id][i];
			//当前结点没有被访问,且以 top_node 为中介点可以使得 next_node 更优
			if (visited[next_node.id] == false)
			{
				if (distance[top_node.id] + next_node.weight < distance[next_node.id])
				{
					distance[next_node.id] = distance[top_node.id] + next_node.weight;
					CityNode node;
					node.id = next_node.id;
					node.weight = distance[next_node.id];		 //更新当前的最短距离
					p_queue.push(node);							 //将所遍历的结点加入到队列中
					parent[next_node.id].clear();				 //清空parent 当前结点数组
					parent[next_node.id].push_back(top_node.id); //更新所遍历结点的父结点
				}
				else if (distance[top_node.id] + next_node.weight == distance[next_node.id]) //表示最短距离相等
				{
					parent[next_node.id].push_back(top_node.id); //更新所遍历结点的父结点
				}
			}
		}
	}
}

void dfs(int start_node, int end_node)
{

	if (end_node == start_node)
	{
		temp_path.push_back(end_node);
		int value = 0;
		for (int i = temp_path.size() - 1; i > 0; i--)
		{
			int id = temp_path[i];
			int id_next = temp_path[i - 1];
			value += money[id][id_next];
		}
		if (value < min_money)
		{
			min_money = value;
			path = temp_path;
		}
		temp_path.pop_back();
		return;
	}
	temp_path.push_back(end_node);
	for (int i = 0; i < parent[end_node].size(); i++)
	{
		dfs(start_node, parent[end_node][i]);
	}
	temp_path.pop_back();
}

void print_path(vector<int> &path)
{
	for (int i = path.size() - 1; i >= 0; i--)
	{
		cout << path[i] << " ";
	}
}

//PAT_A_1030
int main()
{

	int n, m, st, ed; //结点数,边数,起始结点,结束结点
	cin >> n >> m >> st >> ed;
	vector<CityNode> matrix[city_max_num];
	int from_node, to_node, weight, v_money;
	CityNode node;
	map<int, int> distance;

	//初始化distance
	for (int i = 0; i < n; i++)
	{
		distance[i] = INT_MAX;
	}
	distance[st] = 0;

	fill(money[0], money[0] + city_max_num * city_max_num, INT_MAX);
	for (int i = 0; i < m; i++)
	{
		cin >> from_node >> to_node >> weight >> v_money;
		money[from_node][to_node] = money[to_node][from_node] = v_money;

		//无向图
		node.id = to_node;
		node.weight = weight;
		matrix[from_node].push_back(node);

		node.id = from_node;
		node.weight = weight;
		matrix[to_node].push_back(node);
	}
	node.id = st;
	node.weight = 0;		  //初始结点到自己的距离为0
	parent[st].push_back(-1); //初始结点的父结点为-1
	//记录当前结点是否被访问
	bool visited[city_max_num];
	fill(visited, visited + city_max_num, false);
	dijkstra(matrix, node, visited, parent, distance);
	dfs(st, ed);
	//打印结果
	print_path(path);
	cout << distance[ed] << " " << min_money;
	system("pause");
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章