1. 程式人生 > >PAT 1030 Travel Plan (30 分)迪傑斯特拉演算法 燚

PAT 1030 Travel Plan (30 分)迪傑斯特拉演算法 燚

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); Mis 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.

Sample Input:

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

Sample Output:

0 2 3 3 40

大意: 給出一張地圖,上面有各個城市以及每個城市間的距離 以及從城市A到城市B所需花費。求從出發點到目的地的最短路徑,如果最短路徑有多條則選出花費最小的那條路徑。

輸入資料:第一行,給定一定數量的城市N個編號為0~N-1,再給出N個城市間有M條路,以及旅遊的出發點S和目的地D。

                 後面M行:給出兩個城市A,B  以及城市間的距離Len  從A到B 或者 從B到A 所需花費

輸出資料:輸出從出發點S到目的地D 所經過的城市編號   以及S到D的最短路徑距離   總的花費

解題思想:該題為單源最短路徑問題,因此選擇迪傑斯特拉演算法。唯一難度就是在最短路徑有多條的情況下選擇花費最短的一條(普通迪傑斯特拉演算法為隨機選擇一條)。

關於圖的儲存:1.鄰接連結串列,2.鄰接矩陣 ,3用vector建立一個類似鄰接連結串列的長短不一的二維陣列(比鄰接矩陣更節約空間,又能隨機訪問,)結合了前兩種儲存方式的優點

知識點:最優子結構思想     迪傑斯特拉演算法

此題為單源最短路徑演算法的應用  沒有坑。


#include<iostream>
#include<algorithm>
#include<vector>
#include<stack>
using namespace std;
struct Node {
	int distance = 1000;  //到出發點的距離
	int parent = -1;  //儲存該節點的前驅(是從哪個城市到達該節點)
	bool visit = false; //是否已走過這個城市
	int cast = 0;  //從出發點到該城市的花費
};
//DC 為圖的節點A
struct DC {
	int node; // 儲存與該城市A相連的城市B的編號
	int len;  //兩城市間的距離
	int cast;  //兩城市間的花費
};
vector<DC>G[500]; //建立二維陣列的頭
//輸入
void input(int n) {
	for (int i = 0; i < n; i++) {
		int node1, node2; //城市A,B的編號
		DC temp;
		cin >> node1 >> node2 >> temp.len >> temp.cast;
		temp.node = node2;
		G[node1].push_back(temp); //在G[A]的vector中加入B
		temp.node = node1;
		G[node2].push_back(temp);//在G[B]的vector中加入A
	}
}
//計算最短路徑
void compute(vector<Node> &nodes, int s, int d) {
	//將出發點設為訪問  自身到自身的距離為0
	nodes[s].visit = true;
	nodes[s].distance = 0;
	//不斷迴圈  直到到達目的地為止
	while (!nodes[d].visit) {
		//訪問與s城市相連線的其他城市
		for (int i = 0; i < G[s].size(); i++) { 
			 //如果該城市沒有被訪問過 則比較他之前的距離資訊與從s點到該城市的距離,決定是否更新該城市資訊
			if (!nodes[G[s][i].node].visit) {  
				if (nodes[G[s][i].node].distance > G[s][i].len + nodes[s].distance) {
					nodes[G[s][i].node].distance = G[s][i].len + nodes[s].distance;//出發點到s點的距離加上s點到該點的距離
					nodes[G[s][i].node].parent = s;
					nodes[G[s][i].node].cast = G[s][i].cast + nodes[s].cast;//出發點的花費加上s點到該點的花費
				}
				//如果該城市的距離資訊與從s點到達該城市的距離相等  則比較花費 來決定是否更新資訊
				else if (nodes[G[s][i].node].distance == G[s][i].len + nodes[s].distance&&nodes[G[s][i].node].cast > G[s][i].cast + nodes[s].cast) {
					nodes[G[s][i].node].distance = G[s][i].len + nodes[s].distance;
					nodes[G[s][i].node].parent = s;
					nodes[G[s][i].node].cast = G[s][i].cast + nodes[s].cast;
				}
			}
		}
		int min;
		//找到一個還沒被訪問的節點其編號賦值給min
		for (int i = 0; i < nodes.size(); i++) {
			if (!nodes[i].visit) {
				min = i;
				break;
			}
		}
		//找到所有沒有被訪問的點中距出發點最短的那個點
		for (int i = 0; i < nodes.size(); i++) {
			if ((!nodes[i].visit) && nodes[i].distance < nodes[min].distance) {
				min = i;
			}
		}
		s = min;//將距離最小的點的編號賦值給s
		nodes[min].visit = true;//將該節點設定為已訪問過
	}
}
int main() {
	int n, m, s, d;
	cin >> n >> m >> s >> d;
	input(m);
	vector<Node> nodes(n);
	compute(nodes, s, d);
	//因為每個節點中儲存有他的前驅(從那個點到達該點的)所以可以從目的點反向尋找,因此用棧儲存
	stack<int> st; 
	while (d != s) {
		st.push(d);
		d = nodes[d].parent;
	}
	int allLen = 0, allCast = 0;
	cout << s << " ";
	while (st.size()>1) {
		cout << st.top() << " ";
		st.pop();
	}
	cout << st.top() << " " << nodes[st.top()].distance << " " << nodes[st.top()].cast << endl;
}