Timus 1016. A Cube on the Walk

Timus 1016. A Cube on the Walk 要求给出一个立方体在国际象棋棋盘上的最短路径。

1016. A Cube on the Walk

Time Limit: 2.0 second
Memory Limit: 16 MB
A cube placed on some square of a usual chessboard. A cube completely covers one square of the chessboard but not anything more, i.e. size of cube’s edge is equal to the size of square’s edge. The integer number N (0 ≤  N ≤ 1000) is written on the each side of the cube. However it does not imply that the same number is written on all sides. On the different sides there are might be different numbers. One can move a cube to the next square by rotating it around the common edge of the cube and the square. During this motion the sum of the numbers on the bottom of the cube is calculated (each number is added as much times as it appeared at the bottom of the cube). Your task is to find the route between two given squares with the minimal sum of numbers on the bottom side. The numbers on the bottom at the beginning and at the end of walk are also counted. The start and the end positions are different.

Input

The only line of the input contains the necessary data set (only spaces used as delimiters). First, the start position is given, and then the end position. Each position is composed from the character (from ‘a’ to ‘h’ inclusively, it defines the number of the column on the chessboard) and the digit (from ‘1’ to ‘8’ inclusively, it defines the number of the row). That positions are followed by 6 numbers which are currently written on the forward, backward, top, right, bottom and left sides of the cube correspondingly.

Output

The only line of the output must contain the minimal sum followed by the optimal route (one of possible routes with minimal sum). The route must be represented by the sequence of cube’s positions during the walk. It begins with the start square and ends with the finish square. All square positions on the chessboard should be given in the same format as in input. Use spaces as delimiters.

Sample

input output
e2 e3 0 8 1 2 1 1
5 e2 d2 d1 e1 e2 e3
Problem Source: Ural State University Internal Contest '99 #2
Timus 1016. A Cube on the Walk

这道题目是说,一个立方体放在国际象棋棋盘的一个格子上,该立方体每一面都和棋盘的格子一样大。该立方体每一面都标有一个非负整数。你可以在棋盘上滚动该立方体,在这期间计算立方体底面数字的和。你的任务是找出一条从给定的起点到终点的路径,使得前面所说的和最小。

输入只有一行,使用空格作为分隔符。首先是棋盘上的起点和终点的坐标,然后是立方体上的六个整数,按顺序为:前、后、顶、右、底、左面。举例如下: e2 e3 0 8 1 2 1 1

输出也只有一行,使用空格作为分隔符。首先是所求的最小的和。然后依次给出所求的路径的坐标。举例如下:5 e2 d2 d1 e1 e2 e3 。这个路径共六步,其长度为:1 + 1 + 0 + 1 + 1 + 1 = 5

上面的输入和输出的例子是题目中给出的。其实同一个输入可能不止一条最短路径。例如使用我的程序得到的输出如下:5 e2 e1 f1 f2 e2 e3 。这个路径也是六步,其长度为: 1 + 0 + 2 + 1 + 0 + 1 = 5

Timus 1016. A Cube on the Walk Timus 1016. A Cube on the Walk
Timus 1016. A Cube on the Walk

好了,我们还是来看程序吧。

第 43 到 116 行的 Cube 类代表立方体。

第 45 到 47 行的 X、Y、Z 表示立方体绕三个坐标轴旋转,如图所示。

第 48 行的 DCube 数组的四个元素表示立方体在棋盘上向“左、上、右、下”滚动。与此相对应的第 53 行的 DSize 数组的四个元素表示与棋盘当前格子相邻的“左、上、右、下”格子。

第 49 行的 Levels 数组共有 24 个元素,表示同一立方体的 24 种不同的状态,是通过调用第 106 到 115 行的 GetLevels 方法得到的。类似地,“Timus 1015. Test the Difference! 要求将赌场中的骰子分类” 中每种骰子也对应 24 种不同的状态。

程序的主体是第 123 到 130 行的 Run 方法。该方法的第 126 行调用 Read 方法获取输入。然后在第 127 行调用 Dijkstra 方法寻找最短路径。最后在第 128 到 129 行输出结果。

第 142 到 164 行的 Dijkstra 方法是程序的关键部分。第 144 行的三维数组 prev 用来记录立方体的路径,由 24 层的 8x8 棋盘构成。第 145 行的优先队列 q 的元素类型是 Rectangle,其构造函数的参数是 new Comparer() 。Comparer 类在第 11 到 17 行定义,用于逆序比较 Rectangle 的 Width 属性,该 Width 属性表示所求的最小的和。第 146 行将立方体的初始位置压入优先队列。第 147 行的三维数组 dist 大小是 8x8x24,用来记录路径长度,其元素被初始化为无穷大。第 150 到 162 行的循环使用 Dijkstra 算法寻找最短路径。最后在第 163 行调用 GetPath 方法返回找到的最短路径。

  1  using  System;
  2  using  System.IO;
  3  using  System.Drawing;
  4  using  System.Collections.Generic;
  5 
  6  namespace  Skyiv.Ben.Timus
  7  {
  8     //   http://acm.timus.ru/problem.aspx?space=1 &num=1016
  9     sealed   class  T1016
 10    {
 11       sealed   class  Comparer : IComparer < Rectangle >
 12      {
 13         public   int  Compare(Rectangle x, Rectangle y)
 14        {
 15           return  (x.Width  ==  y.Width)  ?   0  : ((x.Width  <  y.Width)  ?   1  :  - 1 );
 16        }
 17      }
 18    
 19       sealed   class  PriorityQueue < T >
 20      {
 21        List < T >  queue  =   new  List < T > ();
 22        IComparer < T >  comparer;
 23        
 24         public  PriorityQueue(IComparer < T >  comparer)
 25        {
 26           this .comparer  =  comparer;
 27        }
 28        
 29         public   void  Push(T v)
 30        {
 31           int  i  =  queue.BinarySearch(v, comparer);
 32          queue.Insert((i  <   0 ?   ~ i : i, v);
 33        }
 34        
 35         public  T Pop()
 36        {
 37          T v  =  queue[queue.Count  -   1 ];
 38          queue.RemoveAt(queue.Count  -   1 );
 39           return  v;
 40        }
 41      }
 42      
 43       sealed   class  Cube : IEquatable < Cube > , IComparable < Cube >
 44      {
 45         static   readonly  Cube X  =   new  Cube( 0 1 5 2 3 4 );
 46         static   readonly  Cube Y  =   new  Cube( 2 4 1 3 0 5 );
 47         static   readonly  Cube Z  =   new  Cube( 3 5 2 1 4 0 );
 48         static   readonly  Cube[] DCube  =  { X, Y, X  *  X  *  X, Y  *  Y  *  Y };
 49         static   readonly  Cube[] Levels  =  GetLevels();
 50         static   readonly   int  idxBottom  =   4 ;
 51         public   static   readonly   int  Size  =   8 //  for chessboard: 8x8
 52         public   static   readonly   int  Level  =  Levels.Length;  //  24
 53         public   static   readonly  Size[] DSize  =  {  new  Size( - 1 , 0 ),  new  Size( 0 , 1 ),  new  Size( 1 , 0 ),  new  Size( 0 , - 1 ) };
 54        
 55         int [] v  =   new   int [ 6 ];  //  Forward, Backward, Top, Right, Bottom, Left
 56         public   int  Bottom {  get  {  return  v[idxBottom]; } }
 57        
 58        Cube()
 59        {
 60           for  ( int  i  =   0 ; i  <  v.Length; i ++ ) v[i]  =  i;
 61        }
 62        
 63         public  Cube( params   int [] v)
 64        {
 65           for  ( int  i  =   0 ; i  <  v.Length; i ++ this .v[i]  =  v[i];
 66        }
 67        
 68         public   bool  Equals(Cube other)
 69        {
 70           return  CompareTo(other)  ==   0 ;
 71        }
 72        
 73         public   int  CompareTo(Cube other)
 74        {
 75           int  i  =   0 ;
 76           while  (i  <  v.Length  &&  v[i]  ==  other.v[i]) i ++ ;
 77           return  (i  ==  v.Length)  ?   0  : ((v[i]  <  other.v[i])  ?   - 1  :  1 );
 78        }
 79        
 80         public   static  Cube  operator * (Cube x, Cube y)
 81        {
 82          Cube z  =   new  Cube();
 83           for  ( int  i  =   0 ; i  <  z.v.Length; i ++ ) z.v[y.v[i]]  =  x.v[i];
 84           return  z;
 85        }
 86        
 87         public   static  Cube  operator / (Cube x, Cube y)
 88        {
 89          Cube z  =   new  Cube();
 90           for  ( int  i  =   0 ; i  <  z.v.Length; i ++ ) z.v[i]  =  y.v[x.v[i]];
 91           return  z;
 92        }
 93 
 94         public   static   int  GetLevel( int  level,  int  n)
 95        {
 96           return  Array.BinarySearch(Levels, Levels[level]  /  DCube[n]);
 97        }
 98        
 99         public   int  GetBottom( int  level)
100        {
101           int  i  =   0 ;
102           while  (Levels[level].v[i]  !=  idxBottom) i ++ ;
103           return  v[i];
104        }
105        
106         static  Cube[] GetLevels()
107        {
108          List < Cube >  list  =   new  List < Cube > ();
109          Cube v, x  =   new  Cube(), y  =   new  Cube(), z  =   new  Cube();
110           for  ( int  i  =   0 ; i  <   4 ; i ++ , x  *=  X)
111             for  ( int  j  =   0 ; j  <   4 ; j ++ , y  *=  Y)
112               for  ( int  n, k  =   0 ; k  <   4 ; k ++ , z  *=  Z)
113                 if  ((n  =  list.BinarySearch(v  =  x  *  y  *  z))  <   0 ) list.Insert( ~ n, v);
114           return  list.ToArray();
115        }
116      }
117      
118       static   void  Main()
119      {
120         new  T1016().Run(Console.In, Console.Out);
121      }
122      
123       void  Run(TextReader reader, TextWriter writer)
124      {
125        Point start, end;
126        Cube cube  =  Read(reader,  out  start,  out  end);
127        Point[] path  =  Dijkstra(cube, start, end);
128        writer.Write(path[ 0 ].X);
129         for  ( int  i  =   1 ; i  <  path.Length; i ++ ) writer.Write(PutPosition(path[i]));
130      }
131      
132      Cube Read(TextReader reader,  out  Point start,  out  Point end)
133      {
134         string [] ss  =  reader.ReadLine().Split();
135        start  =  GetPosition(ss[ 0 ]);
136        end  =  GetPosition(ss[ 1 ]);
137         int [] v  =   new   int [ss.Length  -   2 ];
138         for  ( int  i  =   0 ; i  <  v.Length; i ++ ) v[i]  =   int .Parse(ss[i  +   2 ]);
139         return   new  Cube(v);
140      }
141      
142      Point[] Dijkstra(Cube cube, Point start, Point end)
143      {
144        Rectangle[,,] prev  =   new  Rectangle[Cube.Size, Cube.Size, Cube.Level];
145        PriorityQueue < Rectangle >  q  =   new  PriorityQueue < Rectangle > ( new  Comparer());
146        q.Push( new  Rectangle(start.X, start.Y, cube.Bottom,  0 ));
147         int [,,] dist  =  GetDistance();
148        dist[start.X, start.Y,  0 =  cube.Bottom;
149        Rectangle v;
150         while  ((v  =  q.Pop()).Location  !=  end)
151           if  (v.Width  <=  dist[v.X, v.Y, v.Height])
152             for  ( int  i  =   0 ; i  <  Cube.DSize.Length; i ++ )
153            {
154              Point pt  =  v.Location  +  Cube.DSize[i];
155               if  (pt.X  <   0   ||  pt.Y  <   0   ||  pt.X  >=  Cube.Size  ||  pt.Y  >=  Cube.Size)  continue ;
156               int  height  =  Cube.GetLevel(v.Height, i);
157               int  width  =  v.Width  +  cube.GetBottom(height);
158               if  (dist[pt.X, pt.Y, height]  <=  width)  continue ;
159              dist[pt.X, pt.Y, height]  =  width;
160              prev[pt.X, pt.Y, height]  =  v;
161              q.Push( new  Rectangle(pt.X, pt.Y, width, height));
162            }
163         return  GetPath(prev, start, end, v.Height, dist[end.X, end.Y, v.Height]);
164      }
165      
166      Point[] GetPath(Rectangle[,,] prev, Point start, Point end,  int  id,  int  len)
167      {
168        Stack < Point >  path  =   new  Stack < Point > ();
169         for  (Rectangle v  =   new  Rectangle(end.X, end.Y,  0 , id);
170          v.Location  !=  start  ||  v.Height  !=   0 ;
171          v  =  prev[v.X, v.Y, v.Height]) path.Push(v.Location);
172        path.Push(start);
173        path.Push( new  Point(len,  0 ));
174         return  path.ToArray();
175      }
176      
177       int [,,] GetDistance()
178      {
179         int [,,] dist  =   new   int [Cube.Size, Cube.Size, Cube.Level];
180         for  ( int  i  =   0 ; i  <  dist.GetLength( 0 ); i ++ )
181           for  ( int  j  =   0 ; j  <  dist.GetLength( 1 ); j ++ )
182             for  ( int  k  =   0 ; k  <  dist.GetLength( 2 ); k ++ )
183              dist[i, j, k]  =   int .MaxValue;  //  infinity
184         return  dist;
185      }
186      
187      Point GetPosition( string  s)
188      {
189         return   new  Point(s[ 0 -   ' a ' , s[ 1 -   ' 1 ' );
190      }
191      
192       string  PutPosition(Point pt)
193      {
194         return   string .Format( "  {0}{1} " , ( char )(pt.X  +   ' a ' ), pt.Y  +   1 );
195      }
196    }
197  }


返回目录

你可能感兴趣的:(cube)