1. 程式人生 > 其它 >PAT(甲級)2019年秋季考試 7-4 Dijkstra Sequence (30 分) 凌宸1642

PAT(甲級)2019年秋季考試 7-4 Dijkstra Sequence (30 分) 凌宸1642

PAT(甲級)2019年秋季考試 7-4 Dijkstra Sequence (30 分)

題目描述:

Dijkstra's algorithm is one of the very famous greedy algorithms. It is used for solving the single source shortest path problem which gives the shortest paths from one particular source vertex to all the other vertices of the given graph. It was conceived by computer scientist Edsger W. Dijkstra in 1956 and published three years later.

In this algorithm, a set contains vertices included in shortest path tree is maintained. During each step, we find one vertex which is not yet included and has a minimum distance from the source, and collect it into the set. Hence step by step an ordered sequence of vertices, let's call it Dijkstra sequence

, is generated by Dijkstra's algorithm.

On the other hand, for a given graph, there could be more than one Dijkstra sequence. For example, both { 5, 1, 3, 4, 2 } and { 5, 3, 1, 2, 4 } are Dijkstra sequences for the graph, where 5 is the source. Your job is to check whether a given sequence is Dijkstra sequence or not.

譯:Dijkstra 演算法是很有名的貪心演算法之一。它用於解決單源最短路徑問題,該問題給出從一個特定源頂點到給定圖的所有其他頂點的最短路徑。它由電腦科學家 Edsger W. Dijkstra 於 1956 年構思,並於三年後發表。

在該演算法中,維護一個包含最短路徑樹中包含的頂點的集合。 在每一步中,我們找到一個尚未包含的頂點,並且與源的距離最小,並將其收集到集合中。 因此,一個有序的頂點序列,我們稱之為 Dijkstra 序列,是由 Dijkstra 演算法逐步生成的。

另一方面,對於給定的圖,可能有多個 Dijkstra 序列。 例如,{ 5, 1, 3, 4, 2 } 和 { 5, 3, 1, 2, 4 } 都是圖的 Dijkstra 序列,其中 5 是源。 你的工作是檢查給定的序列是否是 Dijkstra 序列。


Input Specification (輸入說明):

Each input file contains one test case. For each case, the first line contains two positive integers Nv (≤10 3) and Ne (≤10 5), which are the total numbers of vertices and edges, respectively. Hence the vertices are numbered from 1 to Nv.

Then Ne lines follow, each describes an edge by giving the indices of the vertices at the two ends, followed by a positive integer weight (≤100) of the edge. It is guaranteed that the given graph is connected.

Finally the number of queries, K, is given as a positive integer no larger than 100, followed by K lines of sequences, each contains a permutationof the Nv vertices. It is assumed that the first vertex is the source for each sequence.

All the inputs in a line are separated by a space.

譯:每個輸入檔案包含一個測試用例,對於每種情況,第一行包含兩個整數Nv (≤10 3) 和 Ne (≤10 5), 分別代表頂點總數和邊的總數。因此,頂點從 1 到 N 編號。

接下來 Ne 行,每行給出一條邊的描述:邊的端點的索引號以及一個表示邊權 weight (≤100) 的整數。題目保證給定的圖是聯通的。

最後是查詢次數 K ,一個不超過 100 的正整數,接下來 K 行,每行包含一個 Nv 個頂點的排列,預設第一個頂點是每個序列的起點。

所有在一行中的輸入數字都用一個空格隔開。


Output Specification (輸出說明):

For each of the K sequences, print in a line Yes if it is a Dijkstra sequence, or No if not.

譯:對於 K 個序列中的每一個序列,如果它是一個 Dijkstra 序列,則列印 Yes 否則列印 No


Sample Input (樣例輸入):

5 7
1 2 2
1 5 1
2 3 1
2 4 1
2 5 2
3 5 1
3 4 1
4
5 1 3 4 2
5 3 1 2 4
2 3 4 5 1
3 2 1 5 4

Sample Output (樣例輸出):

Yes
Yes
Yes
No

The Idea:

題目意思很簡單,可惜考試的時候沒有做出來,其實就是規定一個圖,然後給定一些頂點訪問序列,判斷該序列是否可以是 Dijkstra 演算法過程中遍歷產生的序列。

其實可以套 Dijkstra 演算法的模板,奈何我太菜了,想不起來,唉!


The Codes:

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1010 ;
const int inf = 0x3f3f3f3f ;
int g[maxn][maxn] ;
int d[maxn] ;
bool vis[maxn] ;
int nv , ne , k ;
bool isDijkstraSeq(vector<int> num){
    // 初始化
	fill(d , d + maxn , inf) ;
	memset(vis , false, sizeof(vis)) ;
	d[num[1]] = 0 ;
    // n - 1 重迴圈
	for(int i = 1 ; i < nv ; i ++){
		int minv = inf ; 
		set<int> st ;
		for(int j = 1 ; j <= nv ; j ++){ // 找當前最小的 d[j]
			if(vis[j] == false && d[j] < minv){ // 更新 d[j]
				st.clear() ;
				st.insert(j) ;
				minv = d[j] ;
			}else if(vis[j] == false && d[j] == minv) st.insert(j) ; // 相同 d[j] 加入備選
		} 
		int u = num[i] ;
		if(!st.count(u)) return false ;
		vis[u] = true ;
        // 鬆弛
		for(int v = 1 ; v <= nv ; v ++){
			if(vis[v] == false && g[u][v] != inf && d[u] + g[u][v] < d[v]){
				d[v] = d[u] + g[u][v] ;
			}
		}
	} 
	return true ;
}
int main(){
	fill(g[0] , g[0] + maxn * maxn , inf) ; 
	scanf("%d%d" , &nv , &ne) ;
	int a , b , c ;
	for(int i = 0 ; i < ne ; i ++){ // 輸入圖 
		scanf("%d%d%d" , &a , &b , &c) ; 
		g[b][a] = g[a][b] = c ;
	}
	scanf("%d" , &k) ;
	for(int i = 0 ; i < k ; i ++){
		vector<int> num(nv + 1) ;
		for(int j = 1 ; j <= nv ; j ++) scanf("%d" , &num[j]) ;
		if(isDijkstraSeq(num)) printf("Yes\n") ;
		else printf("No\n") ;
	}
	return 0 ;
}

The Result :