CCF系列之I’m stuck!(201312-5)
试题名称: I’m stuck!
时间限制: 1.0s
内存限制: 256.0MB
问题描述:
'#': 任何时候玩家都不能移动到此方格;
'+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
'-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
'|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
'.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
此外,玩家不能移动出地图。
请找出满足下面两个性质的方格个数:
1. 玩家可以从初始位置移动到此方格;
2. 玩家不可以从此方格移动到目标位置。
接下来的R行每行都包含C个字符。它们表示地图的格子。地图上恰好有一个'S'和一个'T'。
--+-+
..|#.
..|##
S-+-T
####.
--+-+
..|#X
..|##
S-+-T
####X
解题思路:
1、深度遍历,选择队列。
2、方向和图形符号相互对应。
根据标准代码分析(java):
- package ccf_text2013_12;
- import java.util.*;
- /**
- * I'm stuck!
- * 给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
- '#': 任何时候玩家都不能移动到此方格;
- '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
- '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
- '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
- '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
- 'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
- 'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
- 此外,玩家不能移动出地图。
- 请找出满足下面两个性质的方格个数:
- 1. 玩家可以从初始位置移动到此方格;
- 2. 玩家不可以从此方格移动到目标位置。
- * @author Hello stranger
- *
- */
- public class ImStuck2 {
- public static void main(String[] args) {
- new ImStuck2().run();
- }
- public void run() {
- Scanner fin = new Scanner(System.in);
- int R = fin.nextInt();
- int C = fin.nextInt(); //判断图形的行和列
- String first = fin.nextLine(); //跳过输入的换行(输入行列之后会打一个换行)
- //System.out.println(first);
- int[][] board = new int[R + 2][C + 2];
- char[][] picture = new char[R][C]; //为了验证计算出的结果是否在图形上显示正确
- int rowStart = 0, colStart = 0, rowEnd = 0, colEnd = 0; //起点和终点所在的行列
- for (int i = 1; i <= R; ++i) {
- //读取输入的图形标志,并将图形标志转化为数字标示并保存在数组中,关键在于这些数字
- /**
- * # === 0
- * - === 5
- * | === 0xA == 10
- * + === 0xF == 15
- * S === 0xF == 15
- * T === 0xF == 15
- * . === 0x8 == 8
- *
- */
- String line = fin.nextLine();
- for (int j = 1; j <= C; ++j) {
- char c = line.charAt(j - 1);
- picture[i-1][j-1] = c;
- switch (c) {
- case '#':
- break;
- case '-':
- board[i][j] = 5;
- break;
- case '|':
- board[i][j] = 0xA;
- break;
- case '+':
- case 'S':
- case 'T':
- board[i][j] = 0xF;
- break;
- case '.':
- board[i][j] = 0x8;
- break;
- default:
- break;
- }
- if (c == 'S') {
- rowStart = i;
- colStart = j; //起点所在的行列
- } else if (c == 'T') {
- rowEnd = i;
- colEnd = j; //终点所在的行列
- }
- }
- }
- System.out.println("用户输入的图形为:");
- printCharArray(picture);
- printNumArray(board);
- int[] dr = new int[] { 0, -1, 0, 1 }; //行数 同行、上一行(向上)、 同行、 下一行(向下)
- int[] dc = new int[] { 1, 0, -1, 0 }; //列数 下一列(向右)、 同列、上一列(向左)、同列
- // Scan 1: find all cells which can reach T
- boolean[][] visited = new boolean[R + 2][C + 2]; //默认均为false
- boolean[][] canReachT = new boolean[R + 2][C + 2]; //默认均为false
- initVisited(visited); //数组边框为true,中间为false
- canReachT[rowEnd][colEnd] = true;
- visited[rowEnd][colEnd] = true; //重点的值设为true
- Queue<Integer> queue = new LinkedList<Integer>();
- queue.add(rowEnd);
- queue.add(colEnd); //队列有一个特点就是先进先出,这样就可以采用深度优先遍历
- while (!queue.isEmpty()) {
- int r = queue.remove();
- int c = queue.remove();
- for (int i = 0; i < 4; ++i) {
- int nr = r + dr[i];
- int nc = c + dc[i]; //判断顺序是 向右,向下,向左,向上(四个方向)
- if (visited[nr][nc]) //边框+已经判定可以到达终点的点
- continue;
- if ((board[nr][nc] & (1 << ((i + 2) % 4))) != 0) {
- /**
- * 方向 右 下 左 上
- * i 0 1 2 3
- * t = (i + 2) % 4 2 3 0 1
- * x = 1 << t 4 8 1 2
- * # === 0x0 == 0 & x 0 0 0 0
- * - === 0x5 == 5 & x 4 0 1 0
- * | === 0xA == 10 & x 0 8 0 2
- * + === 0xF == 15 & x 4 8 1 2
- * S === 0xF == 15 & x 4 8 1 2
- * T === 0xF == 15 & x 4 8 1 2
- * . === 0x8 == 8 & x 0 8 0 0
- *
- */
- //将上下左右和数字表示的图标对应起来,如果在这个方向可以走的话,就执行if语句
- canReachT[nr][nc] = true; //这个数组里面值为false的即为玩家不可以从此方格移动到目标位置。
- queue.add(nr);
- queue.add(nc);
- visited[nr][nc] = true;
- }
- }
- }
- printBealoonArray(visited);
- if (!canReachT[rowStart][colStart]) {
- System.out.println("I'm stuck!");
- return;
- }
- // Scan 2: get result 同理
- boolean[][] rCanReach = new boolean[R + 2][C + 2];
- initVisited(visited);
- queue.clear();
- visited[rowStart][colStart] = true;
- rCanReach[rowStart][colStart] = true;
- queue.add(rowStart);
- queue.add(colStart);
- while (!queue.isEmpty()) {
- int r = queue.remove();
- int c = queue.remove();
- for (int i = 0; i < 4; ++i) {
- if ((board[r][c] & (1 << i)) == 0)
- continue;
- int nr = r + dr[i];
- int nc = c + dc[i];
- if (visited[nr][nc])
- continue;
- if (board[nr][nc] == 0)
- continue;
- rCanReach[nr][nc] = true; //这个数组里面值为true的即为玩家可以从初始位置移动到此方格
- queue.add(nr);
- queue.add(nc);
- visited[nr][nc] = true;
- }
- }
- int result = 0;
- //符合两个条件的图所位于的行列
- for (int i = 1; i <= R; ++i) {
- for (int j = 1; j <= C; ++j) {
- if (rCanReach[i][j] && (!canReachT[i][j])){
- ++result;
- picture[i-1][j-1] = 'X';
- }
- }
- }
- System.out.println("经过计算之后的图形为:");
- printCharArray(picture);
- System.out.println("满足条件的位置有 " + result + " 个。");
- }
- /**
- * 预先初始化数组的时候多了边框,因为visited数组默认为false
- * 此函数的目的是使得visited数组边框的默认值变为true
- * 使得visited数组中间的值默认为false
- * @param visited
- */
- private void initVisited(boolean[][] visited) {
- int R = visited.length - 2;
- int C = visited[0].length - 2;
- for (int i = 0; i <= R + 1; ++i) {
- visited[i][0] = true;
- visited[i][C + 1] = true;
- }
- for (int j = 0; j <= C + 1; ++j) {
- visited[0][j] = true;
- visited[R + 1][j] = true;
- }
- for (int i = 1; i <= R; ++i) {
- for (int j = 1; j <= C; ++j) {
- visited[i][j] = false;
- }
- }
- }
- /**
- * 打印数组中保存的值
- * 在此程序中为 输出等价于图形的数字数组
- * @param queue
- */
- public static void printNumArray(int[][] board){
- System.out.println("=======================begin int board array=====================");
- for (int i = 0; i < board.length; ++i) {
- for (int j = 0; j < board[i].length; ++j) {
- System.out.print(board[i][j]+"\t");
- }
- System.out.println();
- }
- System.out.println("===========================end========================");
- }
- /**
- * 打印char数组中保存的值
- * 在此程序中为 输出图形
- * @param queue
- */
- public static void printCharArray(char[][] picture){
- System.out.println("=======================begin char picture array=====================");
- for (int i = 0; i < picture.length; ++i) {
- for (int j = 0; j < picture[i].length; ++j) {
- System.out.print(picture[i][j]);
- }
- System.out.println();
- }
- System.out.println("===========================end========================");
- }
- /**
- * 打印boolean数组中保存的值
- * @param queue
- */
- public static void printBealoonArray(boolean[][] visted){
- System.out.println("=======================begin Boolean visted array =====================");
- for (int i = 0; i < visted.length; ++i) {
- for (int j = 0; j < visted[i].length; ++j) {
- System.out.print(visted[i][j]+"\t");
- }
- System.out.println();
- }
- System.out.println("===========================end========================");
- }
- /**
- * 打印队列中保存的值
- * @param queue
- */
- public static void printQueue(Queue<Integer> queue){
- Iterator it = queue.iterator();
- System.out.println("=======================begin queue=====================");
- int i = 0;
- while(it.hasNext()){
- System.out.print(it.next() + "\t");
- if((++i)%2 == 0){
- System.out.println();
- }
- }
- System.out.println("===========================end========================");
- }
- }
运行结果如下:
标准代码如下(java):
- package ccf_text2013_12;
- import java.util.*;
- /**
- * I'm stuck!
- * 给定一个R行C列的地图,地图的每一个方格可能是'#', '+', '-', '|', '.', 'S', 'T'七个字符中的一个,分别表示如下意思:
- '#': 任何时候玩家都不能移动到此方格;
- '+': 当玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
- '-': 当玩家到达这一方格后,下一步可以向左右两个方向相邻的一个非'#'方格移动一格;
- '|': 当玩家到达这一方格后,下一步可以向上下两个方向相邻的一个非'#'方格移动一格;
- '.': 当玩家到达这一方格后,下一步只能向下移动一格。如果下面相邻的方格为'#',则玩家不能再移动;
- 'S': 玩家的初始位置,地图中只会有一个初始位置。玩家到达这一方格后,下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格;
- 'T': 玩家的目标位置,地图中只会有一个目标位置。玩家到达这一方格后,可以选择完成任务,也可以选择不完成任务继续移动。如果继续移动下一步可以向上下左右四个方向相邻的任意一个非'#'方格移动一格。
- 此外,玩家不能移动出地图。
- 请找出满足下面两个性质的方格个数:
- 1. 玩家可以从初始位置移动到此方格;
- 2. 玩家不可以从此方格移动到目标位置。
- * @author Hello stranger
- *
- */
- public class ImStuck {
- public static void main(String[] args) {
- new ImStuck().run();
- }
- public void run() {
- Scanner fin = new Scanner(System.in);
- int R = fin.nextInt();
- int C = fin.nextInt();
- fin.nextLine();
- int[][] board = new int[R + 2][C + 2];
- int rowStart = 0, colStart = 0, rowEnd = 0, colEnd = 0;
- for (int i = 1; i <= R; ++i) {
- String line = fin.nextLine();
- for (int j = 1; j <= C; ++j) {
- char c = line.charAt(j - 1);
- switch (c) {
- case '#':
- break;
- case '-':
- board[i][j] = 5;
- break;
- case '|':
- board[i][j] = 0xA;
- break;
- case '+':
- case 'S':
- case 'T':
- board[i][j] = 0xF;
- break;
- case '.':
- board[i][j] = 0x8;
- break;
- default:
- break;
- }
- if (c == 'S') {
- rowStart = i;
- colStart = j;
- } else if (c == 'T') {
- rowEnd = i;
- colEnd = j;
- }
- }
- }
- int[] dr = new int[] { 0, -1, 0, 1 };
- int[] dc = new int[] { 1, 0, -1, 0 };
- // Scan 1: find all cells which can reach T
- boolean[][] visited = new boolean[R + 2][C + 2];
- boolean[][] canReachT = new boolean[R + 2][C + 2];
- initVisited(visited);
- canReachT[rowEnd][colEnd] = true;
- visited[rowEnd][colEnd] = true;
- Queue<Integer> queue = new LinkedList<Integer>();
- queue.add(rowEnd);
- queue.add(colEnd);
- while (!queue.isEmpty()) {
- int r = queue.remove();
- int c = queue.remove();
- for (int i = 0; i < 4; ++i) {
- int nr = r + dr[i];
- int nc = c + dc[i];
- if (visited[nr][nc])
- continue;
- if ((board[nr][nc] & (1 << ((i + 2) % 4))) != 0) {
- canReachT[nr][nc] = true;
- queue.add(nr);
- queue.add(nc);
- visited[nr][nc] = true;
- }
- }
- }
- /*
- * for (int i = 1; i <= R; ++i) { for (int j = 1; j <= C; ++j) { if
- * (canReachT[i][j]) { System.out.println("i = " + i + ", j = " + j); }
- * } }
- */
- if (!canReachT[rowStart][colStart]) {
- System.out.println("I'm stuck!");
- return;
- }
- // Scan 2: get result
- boolean[][] rCanReach = new boolean[R + 2][C + 2];
- initVisited(visited);
- queue.clear();
- visited[rowStart][colStart] = true;
- rCanReach[rowStart][colStart] = true;
- queue.add(rowStart);
- queue.add(colStart);
- while (!queue.isEmpty()) {
- int r = queue.remove();
- int c = queue.remove();
- for (int i = 0; i < 4; ++i) {
- if ((board[r][c] & (1 << i)) == 0)
- continue;
- int nr = r + dr[i];
- int nc = c + dc[i];
- if (visited[nr][nc])
- continue;
- if (board[nr][nc] == 0)
- continue;
- rCanReach[nr][nc] = true;
- queue.add(nr);
- queue.add(nc);
- visited[nr][nc] = true;
- }
- }
- int result = 0;
- for (int i = 1; i <= R; ++i) {
- for (int j = 1; j <= C; ++j) {
- /*
- * if (rCanReach[i][j]) { System.out.println("i = " + i +
- * ", j = " + j); }
- */
- if (rCanReach[i][j] && (!canReachT[i][j]))
- ++result;
- }
- }
- System.out.println(result);
- }
- private void initVisited(boolean[][] visited) {
- int R = visited.length - 2;
- int C = visited[0].length - 2;
- for (int i = 0; i <= R + 1; ++i) {
- visited[i][0] = true;
- visited[i][C + 1] = true;
- }
- for (int j = 0; j <= C + 1; ++j) {
- visited[0][j] = true;
- visited[R + 1][j] = true;
- }
- for (int i = 1; i <= R; ++i) {
- for (int j = 1; j <= C; ++j) {
- visited[i][j] = false;
- }
- }
- }
- }
CCF系列之I’m stuck!(201312-5)的更多相关文章
- CCF系列奖获奖名单公布,鲍虎军、周志华获CCF王选奖 | CNCC 2017
本文讲的是CCF系列奖获奖名单公布,鲍虎军.周志华获CCF王选奖 | CNCC 2017, 由中国计算机学会(CCF)主办,福州市人民政府.福州大学承办,福建师范大学.福建工程学院协办的2017中国计 ...
- CCF系列之最优灌溉(201412-4)
试题编号:201412-4试题名称:最优灌溉时间限制: 1.0s内存限制: 256.0MB 问题描述 雷雷承包了很多片麦田,为了灌溉这些麦田,雷雷在第一个麦田挖了一口很深的水井,所有的麦田都从这口井来 ...
- CCF系列之模板生成系统( 201509-3 )
试题名称: 模板生成系统 试题编号: 201509-3 时间限制: 1.0s 内存限制: 256.0MB 问题描述 成成最近在搭建一个网站,其中一些页面的部分内容来自数据库中不同的数据记录,但是页面的 ...
- CCF系列之门禁系统(201412-1)
试题编号:201412-1试题名称:门禁系统时间限制: 2.0s内存限制: 256.0MB 问题描述 涛涛最近要负责图书馆的管理工作,需要记录下每天读者的到访情况.每位读者有一个编号,每条记录用读者的 ...
- CCF系列之Z字形扫描(201412-2)
试题编号:201412-2试题名称:Z字形扫描时间限制: 2.0s内存限制: 256.0MB 问题描述 在图像编码的算法中,需要将一个给定的方形矩阵进行Z字形扫描(Zigzag Scan).给定一个n ...
- CCF系列之字符串匹配(201409-3)
试题编号:201409-3试题名称:字符串匹配时间限制: 1.0s内存限制: 256.0MB 问题描述 给出一个字符串和多行文字,在这些文字中找到字符串出现的那些行.你的程序还需支持大小写敏感选项:当 ...
- CCF系列之画图(201409-2)
试题编号: 201409-2试题名称: 画图时间限制: 1.0s内存限制: 256.0MB问题描述: 问题描述 在一个定义了直角坐标系的纸上,画一个(x1,y1)到(x2,y2)的矩形指将横坐标范围从 ...
- CCF系列之数位之和(201512-1)
试题编号: 201512-1试题名称: 数位之和时间限制: 1.0s内存限制: 256.0MB问题描述: 问题描述 给定一个十进制整数n,输出n的各位数字之和. 输入格式 输入一个整数n. 输出格式 ...
- CCF系列之窗口(201403-2)
试题编号: 201403-2时间限制: 1.0s 内存限制: 256.0MB 问题描述 在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域.窗口的边界上的点也属于该窗口 ...
随机推荐
- vue2.0表单事件的绑定
v-model 1.input type="text" <template> <div id="app"> <label for= ...
- robotframework的学习笔记(十二)------DatabaseLibrary 库
1.安装DatabaseLibrary库 DatabaseLibrary 下载地址:https://pypi.python.org/pypi/robotframework-databaselibrar ...
- [js高手之路]原型式继承与寄生式继承
一.原型式继承本质其实就是个浅拷贝,以一个对象为模板复制出新的对象 function object( o ){ var G = function(){}; G.prototype = o; retur ...
- JS 对象API之修改、删除对象的属性
无论是修改还是删除对象的属性,我们首先要清楚:自有属性.共有属性的处理方法肯定是不同的: 先创建一个对象实例 var obj = { name: '小马扎', age: }; Object.proto ...
- 建造者模式(Builder)-宏观的使用角度
建造者模式(Builder) 建造者模式是用来解决产品对象的创建过程是由多个零件组成的情况,这些零件与产品本身是组合关系,也就是部分与整体,这些零件的创建顺序,还有一些创建中的逻辑,都是稳定的,可以封 ...
- uC/OS-II 内存管理
UC/OS-II 内存管理 1. 简介 uC/OS-II 不使用ANSI编译器的malloc(), free(),因为内存碎片,很可能获取不到一块连续的内存, 这在嵌入式系统中是很危险的.同时 ...
- Minfilter过滤框架
Minfilter过滤框架 优势 与传统的Sfilter过滤驱动相比,有这样几个优势 1. Minfilter加载顺序更易控制,Sfilter加载是随意的,也就是说它在IO设备栈上的顺序是根据其创建的 ...
- Python文章相关性分析---金庸武侠小说分析
百度到<金庸小说全集 14部>全(TXT)作者:金庸 下载下来,然后读取内容with open('names.txt') as f: data = [line.strip() for li ...
- js最常用正则表达式集合
常用正则表达式合集:验证数字:^[0-9]*$验证n位的数字:^\d{n}$验证至少n位数字:^\d{n,}$验证m-n位的数字:^\d{m,n}$验证零和非零开头的数字:^(0|[1-9][0-9] ...
- 3DES加密
本文介绍了3DES加密特性,加密特点,3DES是对称加密,用一个密钥对内容进行加密,必须使用相同的密钥进行解密, 密钥必须配置,而且长度为24位,不足24位,用0位进行补全,本文也顺带介绍了其它加密算 ...