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 x1 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] 表示该路径的长度。
返回目录