zoukankan      html  css  js  c++  java
  • 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]+"	");
    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]+"	");
    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() + "	");
    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 }
  • 相关阅读:
    深入Android 【一】 —— 序及开篇
    Android中ContentProvider和ContentResolver使用入门
    深入Android 【六】 —— 界面构造
    The service cannot be activated because it does not support ASP.NET compatibility. ASP.NET compatibility is enabled for this application. Turn off ASP.NET compatibility mode in the web.config or add the AspNetCompatibilityRequirements attribute to the ser
    Dynamic Business代码片段总结
    对文件的BuildAction以content,resource两种方式的读取
    paraview 3.12.0 windows下编译成功 小记
    百度网盘PanDownload使用Aria2满速下载
    netdata的安装与使用
    用PS给证件照排版教程
  • 原文地址:https://www.cnblogs.com/haimishasha/p/5323639.html
Copyright © 2011-2022 走看看