银河

SKYIV STUDIO

  博客园 :: 首页 :: 博问 :: 闪存 :: :: :: 订阅 订阅 :: 管理 ::
Timus 1004. Sightseeing trip 要求寻找观光旅行的最短路径。

1004. Sightseeing trip

Time Limit: 2.0 second
Memory Limit: 16 MB
There is a travel agency in Adelton town on Zanzibar island. It has decided to offer its clients, besides many other attractions, sightseeing the town. To earn as much as possible from this attraction, the agency has accepted a shrewd decision: it is necessary to find the shortest route which begins and ends at the same place.
Your task is to write a program which finds such a route. In the town there are N crossing points numbered from 1 to N and M two-way roads numbered from 1 to M. Two crossing points can be connected by multiple roads, but no road connects a crossing point with itself. Each sightseeing route is a sequence of road numbers y1, …, yk, k > 2. The road yi (1 ≤ ik − 1) connects crossing points xi and xi+1, the road yk connects crossing points xk and x1. All the numbers x1, …, xk should be different. The length of the sightseeing route is the sum of the lengths of all roads on the sightseeing route, i.e. L(y1) + L(y2) + … + L(yk) where L(yi) is the length of the road yi (1 ≤ ik). Your program has to find such a sightseeing route, the length of which is minimal, or to specify that it is not possible, because there is no sightseeing route in the town.

Input

Input contains a series of tests. The first line of each test contains two positive integers: the number of crossing points N ≤ 100 and the number of roads M ≤ 10000. Each of the next M lines describes one road. It contains 3 positive integers: the number of its first crossing point, the number of the second one, and the length of the road (a positive integer less than 500). Input is ended with a “-1” line.

Output

Each line of output is an answer. It contains either a string “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

inputoutput
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.
Problem Source: Central European Olympiad in Informatics 1999
解答如下:
 1 using System;
 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 != 2return 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 == nullreturn 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 }

这道题目的意思是,给你一张地图,该地图上标明了若干旅游景点,以及各景点之间的道路及其里程。两个景点之间可以有多条道路,但是一条道路必须连接两个景点,而不能绕个圈又回到同一景点。现在你的任务是寻找满足以下条件的一条旅游线路:

  1. 该线路从某一景点出发后必须回到起点。
  2. 该线路至少必须包含三个景点。
  3. 该线路必须是所有可能的线路中最短的。
  4. 该线路不必须包含所有的景点。

上述程序中,第 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] 表示该路径的长度。


返回目录
posted on 2008-12-11 19:19  银河  阅读(2525)  评论(0编辑  收藏  举报