CCF系列之I’m stuck!(201312-5)

试题名称: I’m stuck! 

时间限制: 1.0s 

内存限制: 256.0MB 

问题描述: 

问题描述
  给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
  '#': 任何时候玩家都不能移动到此方格;
  '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
  '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
  '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
  'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
  此外,玩家不能移动出地图。
  请找出满足下面两个性质的方格个数:
  1. 玩家可以从初始位置移动到此方格;
  2. 玩家不可以从此方格移动到目标位置。
输入格式
  输入的第一行包括两个整数R 和C,分别表示地图的行和列数。(1 ≤ R, C ≤ 50)。
  接下来的R行每行都包含C个字符。它们表示地图的格子。地图上恰好有一个'S'和一个'T'。
输出格式
  如果玩家在初始位置就已经不能到达终点了,就输出“I'm stuck!”(不含双引号)。否则的话,输出满足性质的方格的个数。
样例输入
5 5
--+-+
..|#.
..|##
S-+-T
####.
样例输出
2
样例说明
  如果把满足性质的方格在地图上用'X'标记出来的话,地图如下所示:
  --+-+
  ..|#X
  ..|##
  S-+-T
  ####X
 

解题思路: 

    1、深度遍历,选择队列。

    2、方向和图形符号相互对应。

  

    

根据标准代码分析(java):

  

  1 package ccf_text2013_12;
  2 
  3 import java.util.*;
  4 /**
  5  * I'm stuck!
  6  *   给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
  7   '#': 任何时候玩家都不能移动到此方格;
  8   '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  9   '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
 10   '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
 11   '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
 12   'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
 13   'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
 14   此外,玩家不能移动出地图。
 15   请找出满足下面两个性质的方格个数:
 16   1. 玩家可以从初始位置移动到此方格;
 17   2. 玩家不可以从此方格移动到目标位置。
 18  * @author Hello stranger
 19  *
 20  */
 21 public class ImStuck2 {
 22     
 23     public static void main(String[] args) {
 24         
 25         new ImStuck2().run();
 26     }
 27 
 28     public void run() {
 29         
 30         Scanner fin = new Scanner(System.in);
 31         
 32         int R = fin.nextInt();
 33         
 34         int C = fin.nextInt();            //判断图形的行和列
 35         
 36         String first = fin.nextLine();   //跳过输入的换行(输入行列之后会打一个换行)
 37         
 38         //System.out.println(first);
 39         
 40         int[][] board = new int[R + 2][C + 2];
 41         
 42         char[][] picture = new char[R][C];  //为了验证计算出的结果是否在图形上显示正确
 43         
 44         int rowStart = 0, colStart = 0, rowEnd = 0, colEnd = 0;  //起点和终点所在的行列
 45         
 46         for (int i = 1; i <= R; ++i) {    
 47             
 48             //读取输入的图形标志,并将图形标志转化为数字标示并保存在数组中,关键在于这些数字
 49             /**
 50              *   #   ===   0
 51              *   -   ===   5
 52              *   |   ===   0xA   == 10
 53              *   +   ===   0xF   == 15
 54              *   S   ===   0xF   == 15
 55              *   T   ===   0xF   == 15
 56              *   .   ===   0x8   == 8
 57              *   
 58              */
 59             String line = fin.nextLine();
 60             
 61             for (int j = 1; j <= C; ++j) {
 62                 
 63                 char c = line.charAt(j - 1);
 64                 
 65                 picture[i-1][j-1] = c;
 66                 
 67                 switch (c) {
 68                 
 69                 case '#':
 70                     
 71                     break;    
 72                     
 73                 case '-':
 74                     
 75                     board[i][j] = 5;
 76                     
 77                     break;
 78                     
 79                 case '|':
 80                     
 81                     board[i][j] = 0xA;
 82                     
 83                     break;
 84                     
 85                 case '+':
 86                     
 87                 case 'S':
 88                     
 89                 case 'T':
 90                     
 91                     board[i][j] = 0xF;
 92                     
 93                     break;
 94                     
 95                 case '.':
 96                     
 97                     board[i][j] = 0x8;
 98                     
 99                     break;
100                     
101                 default:
102                     
103                     break;
104                     
105                 }
106                 if (c == 'S') {
107                     
108                     rowStart = i;
109                     
110                     colStart = j;                //起点所在的行列
111                     
112                 } else if (c == 'T') {
113                     
114                     rowEnd = i;
115                     
116                     colEnd = j;                    //终点所在的行列
117                 }
118             }
119         }
120         System.out.println("用户输入的图形为:");
121         printCharArray(picture);
122         printNumArray(board);
123         int[] dr = new int[] { 0, -1, 0, 1 };              //行数  同行、上一行(向上)、 同行、 下一行(向下)
124         
125         int[] dc = new int[] { 1, 0, -1, 0 };               //列数 下一列(向右)、 同列、上一列(向左)、同列
126         
127         
128         // Scan 1: find all cells which can reach T
129         
130         boolean[][] visited = new boolean[R + 2][C + 2];      //默认均为false
131                 
132         boolean[][] canReachT = new boolean[R + 2][C + 2];    //默认均为false
133         
134         initVisited(visited);                                //数组边框为true,中间为false
135         
136         canReachT[rowEnd][colEnd] = true;
137         
138         visited[rowEnd][colEnd] = true;                        //重点的值设为true
139         
140         Queue<Integer> queue = new LinkedList<Integer>();
141         
142         queue.add(rowEnd);
143         
144         queue.add(colEnd);                    //队列有一个特点就是先进先出,这样就可以采用深度优先遍历
145         
146         
147         while (!queue.isEmpty()) {
148             
149             int r = queue.remove();
150             
151             int c = queue.remove();
152             
153             for (int i = 0; i < 4; ++i) {
154                 
155                 int nr = r + dr[i];
156                 
157                 int nc = c + dc[i];        //判断顺序是 向右,向下,向左,向上(四个方向)
158                 
159                 if (visited[nr][nc])    //边框+已经判定可以到达终点的点
160                     
161                     continue;
162                 
163                 if ((board[nr][nc] & (1 << ((i + 2) % 4))) != 0) {  
164                     
165                     /**
166                      *   方向                        右    下    左    上
167                      *      i                             0    1    2    3
168                      *      t = (i + 2) % 4             2    3    0    1    
169                      *      x = 1 << t                     4    8    1    2     
170                      *   #   ===   0x0   ==  0    & x  0    0    0    0    
171                      *   -   ===   0x5   ==  5    & x  4    0    1    0
172                      *   |   ===   0xA   == 10    & x  0    8    0    2
173                      *   +   ===   0xF   == 15    & x  4    8    1    2
174                      *   S   ===   0xF   == 15    & x  4    8    1    2
175                      *   T   ===   0xF   == 15    & x  4    8    1    2
176                      *   .   ===   0x8   ==  8    & x  0    8    0    0
177                      *   
178                      */
179                     
180                     //将上下左右和数字表示的图标对应起来,如果在这个方向可以走的话,就执行if语句
181                     
182                     canReachT[nr][nc] = true;   //这个数组里面值为false的即为玩家不可以从此方格移动到目标位置。
183                     
184                     queue.add(nr);
185                     
186                     queue.add(nc);
187                     
188                     visited[nr][nc] = true;
189                 }
190             }
191         }
192         
193         printBealoonArray(visited);
194     
195         if (!canReachT[rowStart][colStart]) {
196             
197             System.out.println("I'm stuck!");
198             
199             return;
200         }
201         // Scan 2: get result  同理
202         
203         boolean[][] rCanReach = new boolean[R + 2][C + 2];
204         
205         initVisited(visited);
206         
207         queue.clear();
208         
209         visited[rowStart][colStart] = true;
210         
211         rCanReach[rowStart][colStart] = true;
212         
213         queue.add(rowStart);
214         
215         queue.add(colStart);
216         
217         while (!queue.isEmpty()) {
218             
219             int r = queue.remove();
220             
221             int c = queue.remove();
222             
223             for (int i = 0; i < 4; ++i) {
224                 
225                 if ((board[r][c] & (1 << i)) == 0)
226                     
227                     continue;
228                 
229                 int nr = r + dr[i];
230                 
231                 int nc = c + dc[i];
232                 
233                 if (visited[nr][nc])
234                     
235                     continue;
236                 
237                 if (board[nr][nc] == 0)
238                     
239                     continue;
240                 
241                 rCanReach[nr][nc] = true;  //这个数组里面值为true的即为玩家可以从初始位置移动到此方格
242                 
243                 queue.add(nr);
244                 
245                 queue.add(nc);
246                 
247                 visited[nr][nc] = true;
248             }
249         }
250         int result = 0;
251         
252         //符合两个条件的图所位于的行列
253         
254         for (int i = 1; i <= R; ++i) {
255             
256             for (int j = 1; j <= C; ++j) {
257                 
258                 if (rCanReach[i][j] && (!canReachT[i][j])){
259                     
260                     ++result;
261                     
262                     picture[i-1][j-1] = 'X';
263                     
264                 }    
265                     
266             }
267         }
268         
269         System.out.println("经过计算之后的图形为:");
270         
271         printCharArray(picture);
272         
273         System.out.println("满足条件的位置有 " + result + " 个。");
274     }
275     
276     /**
277      * 预先初始化数组的时候多了边框,因为visited数组默认为false
278      * 此函数的目的是使得visited数组边框的默认值变为true
279      * 使得visited数组中间的值默认为false
280      * @param visited
281      */
282     
283     private void initVisited(boolean[][] visited) {
284         
285         int R = visited.length - 2;
286         
287         int C = visited[0].length - 2;
288         
289         for (int i = 0; i <= R + 1; ++i) {
290             
291             visited[i][0] = true;
292             
293             visited[i][C + 1] = true;
294         }
295         for (int j = 0; j <= C + 1; ++j) {
296             
297             visited[0][j] = true;
298             
299             visited[R + 1][j] = true;
300         }
301         for (int i = 1; i <= R; ++i) {
302             
303             for (int j = 1; j <= C; ++j) {
304                 
305                 visited[i][j] = false;
306 
307             }
308 
309         }
310 
311     }
312     /**
313      * 打印数组中保存的值
314      * 在此程序中为  输出等价于图形的数字数组
315      * @param queue
316      */
317     public static void printNumArray(int[][] board){
318         
319         System.out.println("=======================begin int board array=====================");
320         
321         for (int i = 0; i < board.length; ++i) {    
322             
323             for (int j = 0; j < board[i].length; ++j) {
324                 
325                 System.out.print(board[i][j]+"\t");
326             }
327             System.out.println();
328         }
329         System.out.println("===========================end========================");
330     }
331     
332     /**
333      * 打印char数组中保存的值
334      * 在此程序中为  输出图形
335      * @param queue
336      */
337     public static void printCharArray(char[][] picture){
338         
339         System.out.println("=======================begin char picture array=====================");
340         
341         for (int i = 0; i < picture.length; ++i) {    
342             
343             for (int j = 0; j < picture[i].length; ++j) {
344                 
345                 System.out.print(picture[i][j]);
346             }
347             System.out.println();
348         }
349         System.out.println("===========================end========================");
350     }
351     
352     /**
353      * 打印boolean数组中保存的值
354      * @param queue
355      */
356     public static void printBealoonArray(boolean[][] visted){
357         
358         System.out.println("=======================begin Boolean visted array =====================");
359         
360         for (int i = 0; i < visted.length; ++i) {    
361             
362             for (int j = 0; j < visted[i].length; ++j) {
363                 
364                 System.out.print(visted[i][j]+"\t");
365             }
366             System.out.println();
367         }
368         System.out.println("===========================end========================");
369     }
370     /**
371      * 打印队列中保存的值
372      * @param queue
373      */
374     public static void  printQueue(Queue<Integer> queue){
375         
376         Iterator it = queue.iterator();
377         
378         System.out.println("=======================begin queue=====================");
379         
380         int i = 0;
381         
382         while(it.hasNext()){
383             
384             System.out.print(it.next() + "\t");
385             
386             if((++i)%2 == 0){
387                 
388                 System.out.println();
389             }
390         }
391         System.out.println("===========================end========================");
392     }
393 }

运行结果如下:

    

   

标准代码如下(java):

  

  1 package ccf_text2013_12;
  2 
  3 import java.util.*;
  4 /**
  5  * I'm stuck!
  6  *   给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
  7   '#': 任何时候玩家都不能移动到此方格;
  8   '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
  9   '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
 10   '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
 11   '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
 12   'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
 13   'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
 14   此外,玩家不能移动出地图。
 15   请找出满足下面两个性质的方格个数:
 16   1. 玩家可以从初始位置移动到此方格;
 17   2. 玩家不可以从此方格移动到目标位置。
 18  * @author Hello stranger
 19  *
 20  */
 21 public class ImStuck {
 22     public static void main(String[] args) {
 23         new ImStuck().run();
 24     }
 25 
 26     public void run() {
 27         Scanner fin = new Scanner(System.in);
 28         int R = fin.nextInt();
 29         int C = fin.nextInt();
 30         fin.nextLine();
 31         int[][] board = new int[R + 2][C + 2];
 32         int rowStart = 0, colStart = 0, rowEnd = 0, colEnd = 0;
 33         for (int i = 1; i <= R; ++i) {
 34             String line = fin.nextLine();
 35             for (int j = 1; j <= C; ++j) {
 36                 char c = line.charAt(j - 1);
 37                 switch (c) {
 38                 case '#':
 39                     break;
 40                 case '-':
 41                     board[i][j] = 5;
 42                     break;
 43                 case '|':
 44                     board[i][j] = 0xA;
 45                     break;
 46                 case '+':
 47                 case 'S':
 48                 case 'T':
 49                     board[i][j] = 0xF;
 50                     break;
 51                 case '.':
 52                     board[i][j] = 0x8;
 53                     break;
 54                 default:
 55                     break;
 56                 }
 57                 if (c == 'S') {
 58                     rowStart = i;
 59                     colStart = j;
 60                 } else if (c == 'T') {
 61                     rowEnd = i;
 62                     colEnd = j;
 63                 }
 64             }
 65         }
 66         int[] dr = new int[] { 0, -1, 0, 1 };
 67         int[] dc = new int[] { 1, 0, -1, 0 };
 68         // Scan 1: find all cells which can reach T
 69         boolean[][] visited = new boolean[R + 2][C + 2];
 70         boolean[][] canReachT = new boolean[R + 2][C + 2];
 71         initVisited(visited);
 72         canReachT[rowEnd][colEnd] = true;
 73         visited[rowEnd][colEnd] = true;
 74         Queue<Integer> queue = new LinkedList<Integer>();
 75         queue.add(rowEnd);
 76         queue.add(colEnd);
 77         while (!queue.isEmpty()) {
 78             int r = queue.remove();
 79             int c = queue.remove();
 80             for (int i = 0; i < 4; ++i) {
 81                 int nr = r + dr[i];
 82                 int nc = c + dc[i];
 83                 if (visited[nr][nc])
 84                     continue;
 85                 if ((board[nr][nc] & (1 << ((i + 2) % 4))) != 0) {
 86                     canReachT[nr][nc] = true;
 87                     queue.add(nr);
 88                     queue.add(nc);
 89                     visited[nr][nc] = true;
 90                 }
 91             }
 92         }
 93         /*
 94          * for (int i = 1; i <= R; ++i) { for (int j = 1; j <= C; ++j) { if
 95          * (canReachT[i][j]) { System.out.println("i = " + i + ", j = " + j); }
 96          * } }
 97          */
 98         if (!canReachT[rowStart][colStart]) {
 99             System.out.println("I'm stuck!");
100             return;
101         }
102         // Scan 2: get result
103         boolean[][] rCanReach = new boolean[R + 2][C + 2];
104         initVisited(visited);
105         queue.clear();
106         visited[rowStart][colStart] = true;
107         rCanReach[rowStart][colStart] = true;
108         queue.add(rowStart);
109         queue.add(colStart);
110         while (!queue.isEmpty()) {
111             int r = queue.remove();
112             int c = queue.remove();
113             for (int i = 0; i < 4; ++i) {
114                 if ((board[r][c] & (1 << i)) == 0)
115                     continue;
116                 int nr = r + dr[i];
117                 int nc = c + dc[i];
118                 if (visited[nr][nc])
119                     continue;
120                 if (board[nr][nc] == 0)
121                     continue;
122                 rCanReach[nr][nc] = true;
123                 queue.add(nr);
124                 queue.add(nc);
125                 visited[nr][nc] = true;
126             }
127         }
128         int result = 0;
129         for (int i = 1; i <= R; ++i) {
130             for (int j = 1; j <= C; ++j) {
131                 /*
132                  * if (rCanReach[i][j]) { System.out.println("i = " + i +
133                  * ", j = " + j); }
134                  */
135                 if (rCanReach[i][j] && (!canReachT[i][j]))
136                     ++result;
137             }
138         }
139         System.out.println(result);
140     }
141 
142     private void initVisited(boolean[][] visited) {
143         int R = visited.length - 2;
144         int C = visited[0].length - 2;
145         for (int i = 0; i <= R + 1; ++i) {
146             visited[i][0] = true;
147             visited[i][C + 1] = true;
148         }
149         for (int j = 0; j <= C + 1; ++j) {
150             visited[0][j] = true;
151             visited[R + 1][j] = true;
152         }
153         for (int i = 1; i <= R; ++i) {
154             for (int j = 1; j <= C; ++j) {
155                 visited[i][j] = false;
156 
157             }
158 
159         }
160 
161     }
162 }

 

转载于:https://www.cnblogs.com/haimishasha/p/5323639.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值