Timus 1004. Sightseeing trip

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 y 1, …, yk, k > 2. The road yi (1 ≤ ik − 1) connects crossing points xi and x i+1, the road yk connects crossing points xk and x 1. All the numbers x 1, …, 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( y 1) + L( y 2) + … + 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 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

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  !=   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  }

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

  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] 表示该路径的长度。


返回目录
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值