• 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 }
  • 相关阅读:
    loading加载动画
    js获取文本的行数
    获取浏览器结尾生成的参数,提交的时候对其做判断
    js获取当前浏览器地址栏的链接,然后在链接后面加参数
    a链接在新窗口打开
    js随机出现2个数字
    css进行中打点效果
    jqeury显示前几个,隐藏后几个,点击后隐藏前几个显示后几个
    jQuery 源码解析(七) jQuery对象和DOM对象的互相转换
    jQuery 源码解析(六) $.each和$.map的区别
  • 原文地址:https://www.cnblogs.com/haimishasha/p/5323639.html
Copyright © 2020-2023  润新知