1004. Sightseeing trip
Memory Limit: 16 MB
Input
-1
” line.
Output
No solution.
” in case there isn't any sightseeing route, or it contains the numbers of all crossing points on the shortest sightseeing route in the order how to pass them (i.e. the numbers
x
1 to
xk from our definition of a sightseeing route), separated by single spaces. If there are multiple sightseeing routes of the minimal length, you can output any one of them.
Sample
input | output |
---|---|
5 7 1 4 1 1 3 300 3 1 10 1 2 16 2 3 100 2 5 15 5 3 20 4 3 1 2 10 1 3 20 1 4 30 -1 | 1 3 5 2 No solution. |
解答如下:
2 using System.IO;
3
4 namespace Skyiv.Ben.Timus
5 {
6 // http://acm.timus.ru/problem.aspx?space=1 &num=1004
7 sealed class T1004
8 {
9 static readonly int infinity = int .MaxValue;
10
11 static void Main()
12 {
13 while (Search(Console.Out, Read(Console.In))) ;
14 }
15
16 static int [,] Read(TextReader reader)
17 {
18 string [] ss = reader.ReadLine().Split();
19 if (ss.Length != 2 ) return null ;
20 int n = int .Parse(ss[ 0 ]);
21 int [,] matrix = new int [n, n];
22 for ( int i = 0 ; i < n; i ++ )
23 for ( int j = 0 ; j < n; j ++ )
24 matrix[i, j] = infinity;
25 for ( int i = int .Parse(ss[ 1 ]); i > 0 ; i -- )
26 {
27 ss = reader.ReadLine().Split();
28 int a = int .Parse(ss[ 0 ]) - 1 ;
29 int b = int .Parse(ss[ 1 ]) - 1 ;
30 matrix[a, b] = matrix[b, a] = Math.Min(matrix[a, b], int .Parse(ss[ 2 ]));
31 }
32 return matrix;
33 }
34
35 static bool Search(TextWriter writer, int [,] matrix)
36 {
37 if (matrix == null ) return false ;
38 int n = matrix.GetLength( 0 ), cnt = 0 , dist = infinity;
39 int [] path = new int [n];
40 for ( int i = 0 ; i < n - 1 ; i ++ )
41 for ( int j = i + 1 ; j < n; j ++ )
42 {
43 int len = matrix[i, j];
44 if (len == infinity) continue ;
45 matrix[i, j] = matrix[j, i] = infinity;
46 int [] prev = Dijkstra(matrix, i, j);
47 if (prev[n] == infinity || dist <= prev[n] + len) continue ;
48 dist = prev[n] + len;
49 cnt = 0 ;
50 for ( int k = j; k != - 1 ; k = prev[k]) path[cnt ++ ] = k + 1 ;
51 }
52 if (dist == infinity) writer.Write( " No solution. " );
53 else for ( int i = 0 ; i < cnt; i ++ ) writer.Write(path[i] + " " );
54 writer.WriteLine();
55 return true ;
56 }
57
58 static int [] Dijkstra( int [,] matrix, int v1, int v2)
59 {
60 int n = matrix.GetLength( 0 );
61 bool [] used = new bool [n];
62 int [] dist = new int [n];
63 int [] prev = new int [n + 1 ];
64 for ( int i = 0 ; i < dist.Length; i ++ ) dist[i] = infinity;
65 dist[v1] = 0 ;
66 prev[v1] = - 1 ;
67 while ( true )
68 {
69 int k = - 1 ;
70 for ( int m = infinity, i = 0 ; i < n; i ++ )
71 if ( ! used[i] && dist[i] < m) m = dist[k = i];
72 prev[n] = (k == - 1 ) ? infinity : dist[k];
73 if (k == - 1 || k == v2) return prev;
74 for ( int i = 0 ; i < n; i ++ )
75 if (matrix[k, i] != infinity && dist[i] > dist[k] + matrix[k, i])
76 dist[i] = dist[prev[i] = k] + matrix[k, i];
77 used[k] = true ;
78 }
79 }
80 }
81 }
这道题目的意思是,给你一张地图,该地图上标明了若干旅游景点,以及各景点之间的道路及其里程。两个景点之间可以有多条道路,但是一条道路必须连接两个景点,而不能绕个圈又回到同一景点。现在你的任务是寻找满足以下条件的一条旅游线路:
- 该线路从某一景点出发后必须回到起点。
- 该线路至少必须包含三个景点。
- 该线路必须是所有可能的线路中最短的。
- 该线路不必须包含所有的景点。
上述程序中,第 16 到 33 行的 Read 方法读取输入的地图到矩阵 matrix 中。matrix 的元素表示各景点间的距离,在第 22 到 24 行中被初始化为无穷大,然后在第 25 到 31 行的 for 循环中读入各景点间的距离,并且如果某两个景点之间有多道路的话,只保留距离最短的一条(第 30 行)。该矩阵是对称的。
第 35 到 56 行的 Search 方法试图找出满足条件的旅游线路。该方法在第 40 到 51 行的双重循环中遍历各景点,如果某两个景点之间有道路相连的话(第 44 行),就在矩阵 matrix 中将该道路断开(第 45 行),然后调用 Dijkstra 方法寻找这两个景点之间的最短线路(第 46 行)。然后就判断并记录最短的环形的(加上刚被断开的道路)旅游线路(第 47 到 50 行)。第 52 到 54 行输出结果。注意,在第 45 行断开的道路不需要重新连接,因为在这次查找中已经是寻找最短线路了,下次不可能有经过这个道路的更短线路了。
第 58 到 79 行的 Dijkstra 方法使用著名的 Dijkstra 算法寻找景点 v1 到 v2 的最短线路。第 60 到 66 行进行必要的初始化工作,第 67 到 78 行的循环使用贪心技术寻找单源最短路径。数组 prev 记录所走的路径,而 prev[n] 表示该路径的长度。
返回目录