算法筆記---【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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章