第十三届蓝桥杯大赛软件赛省赛Java 大学 B 组 解析

1 篇文章 0 订阅
1 篇文章 0 订阅

目录

试题 A: 星期计算

试题 B: 山

试题 C: 字符统计

试题 D: 最少刷题数

试题 E: 求阶乘

试题 F: 最大子矩阵

试题 G: 数组切分

试题 H: 回忆迷宫

试题 I: 红绿灯

试题 J: 拉箱子


试题 A: 星期计算

本题总分: 5
【问题描述】
已知今天是星期六,请问 20 22 天后是星期几?
注意用数字 1 7 表示星期一到星期日。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
import java.math.BigInteger;

/**
 * 星期计算
 * 使用单层for循环
 * @author HP
 * @date 2022/04/28
 */
public class A_WeekCount {
    public static void main(String[] args) {
        BigInteger base = new BigInteger("20");
        int power = 22;
        BigInteger ans = new BigInteger("1");
        for(int i = 1; i <= power; i++) {
          ans = ans.multiply(base);
        }
        System.out.println(ans);
        System.out.println(ans.mod(new BigInteger("7")));
    }
}

试题 B:

本题总分: 5
【问题描述】
这天小明正在学数数。
他突然发现有些正整数的形状像一座“山”,比如 123565321 145541 ,它
们左右对称(回文)且数位上的数字先单调不减,后单调不增。
小明数了很久也没有数完,他想让你告诉他在区间 [2022 , 2022222022] 中有
多少个数的形状像一座“山”。
【答案提交】
这是一道结果填空的题,你只需要算出结果后提交即可。本题的结果为一
个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
import java.math.BigInteger;

/**
 * 星期计算
 * 使用单层for循环
 * @author HP
 * @date 2022/04/28
 */
public class A_WeekCount {
    public static void main(String[] args) {
        BigInteger base = new BigInteger("20");
        int power = 22;
        BigInteger ans = new BigInteger("1");
        for(int i = 1; ipublic class B_Mountain {
    public static void main(String[] args) {
        long start = 2022;
        long end = 2022222022;
        long ans = 0;
        for (long i = start; i <= end; i++) {
            if (check(i)){
                ans++;
                System.out.println(ans);
            }
        }
    }

    /**
     * 检查是否是"山"
     *
     * @param i
     * @return boolean
     */
    public static boolean check(long i){
        String string = String.valueOf(i);
        StringBuilder stringBuilder = new StringBuilder(string);
        if (string.equals(stringBuilder.reverse().toString()) == false){
            return false;
        }
        for (int j = 0; j < string.length() / 2; j++) {
            if (string.charAt(j) > string.charAt(j + 1)){
                return false;
            }
        }
        return true;
    }
} <= power; i++) {
          ans = ans.multiply(base);
        }
        System.out.println(ans);
        System.out.println(ans.mod(new BigInteger("7")));
    }
}

试题 C: 字符统计

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 10
【问题描述】
给定一个只包含大写字母的字符串 S ,请你输出其中出现次数最多的字母。
如果有多个字母均出现了最多次,按字母表顺序依次输出所有这些字母。
【输入格式】
一个只包含大写字母的字符串 S .
【输出格式】
若干个大写字母,代表答案。
【样例输入】
BABBACAC
【样例输出】
AB
【评测用例规模与约定】
对于 100 % 的评测用例, 1 ≤ | S | ≤ 10 6 .
import java.util.HashMap;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeSet;

/**
 * c字符统计
 * 把每个字母出现的次数记录下来, 次数等于最大次数的字母输出
 * @author HP
 * @date 2022/04/28
 */
public class C_CharacterStatistics {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        String string = scanner.nextLine();
        scanner.close();
        HashMap<Character, Integer> hashMap = new HashMap<>();
        int max = 0;
        for (int i = 0; i < string.length(); i++) {
            Character character = string.charAt(i);
            if (hashMap.containsKey(character)){
                hashMap.put(character, hashMap.get(character) + 1);
            }else {
                hashMap.put(character, 1);
            }
            max = Math.max(max, hashMap.get(character));
        }
        TreeSet<Character> treeSet = new TreeSet<>();
        for (Map.Entry<Character, Integer> entry: hashMap.entrySet()){
            if (entry.getValue() == max){
                treeSet.add(entry.getKey());
            }
        }
        for (Character character: treeSet){
            System.out.print(character);
        }
    }
}

试题 D: 最少刷题数

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 10
【问题描述】
小蓝老师教的编程课有 N 名学生,编号依次是 1 . . . N 。第 i 号学生这学期
刷题的数量是 A i
对于每一名学生,请你计算他至少还要再刷多少道题,才能使得全班刷题
比他多的学生数不超过刷题比他少的学生数。
【输入格式】
第一行包含一个正整数 N
第二行包含 N 个整数: A 1 , A 2 , A 3 , . . . , A N .
【输出格式】
输出 N 个整数,依次表示第 1 . . . N 号学生分别至少还要再刷多少道题。
【样例输入】
5
12 10 15 20 6
【样例输出】
0 3 0 0 7
【评测用例规模与约定】
对于 30 % 的数据, 1 N 1000 , 0 A i 1000 .
对于 100 % 的数据, 1 N 100000 , 0 A i 100000 .
import java.util.ArrayList;
import java.util.Comparator;
import java.util.Scanner;

/**
 * d最小数量问题
 * 找出最小的数, 满足: 大于他的数的数量 <= 小于他的数的数量
 * 如果是小于, 小于这个数的数在增加某个数后若有满足上述条件, 则增加之后要比这个数大1
 * 否则, 增加之后等于这个数则可
 * @author HP
 * @date 2022/04/28
 */
public class D_MinimumNumberOfQuestions {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        ArrayList<Integer> noSortArrayList = new ArrayList<>();
        ArrayList<Integer> sortedArrayList = new ArrayList<>();
        int n = scanner.nextInt();
        for (int i = 0; i < n; i++) {
            noSortArrayList.add(scanner.nextInt());
        }
        sortedArrayList.addAll(noSortArrayList);
        sortedArrayList.sort(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                return o1 - o2;
            }
        });
        Integer medium = 0;
        int add = 0;
        for (Integer integer: sortedArrayList){
            medium = integer;
            int start = sortedArrayList.indexOf(integer);
            int end = sortedArrayList.lastIndexOf(integer);
            int lessThan = start;
            int moreThan = n - end - 1;
            if (lessThan > moreThan){
                break;
            }
            if (lessThan == moreThan){
                add = 1;
                break;
            }
        }
        for (Integer integer: noSortArrayList){
            if (integer < medium){
                System.out.print(medium - integer + add);
            }else{
                System.out.print(0);
            }
            System.out.print(" ");
        }
    }
}

试题 E: 求阶乘

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 15
【问题描述】
满足 N ! 的末尾恰好有 K 0 的最小的 N 是多少 ?
如果这样的 N 不存在输出 1
【输入格式】
一个整数 K
【输出格式】
一个整数代表答案。
【样例输入】
2
【样例输出】
10
【评测用例规模与约定】
对于 30 % 的数据, 1 K 10 6 .
对于 100 % 的数据, 1 K 10 18 .
import java.util.Scanner;

/**
 * e找到!
 * 采用二分法
 * @author HP
 * @date 2022/04/28
 */
public class E_FindTheFactorial {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        long n = scanner.nextLong();
        long left = 5;
        long right = Long.MAX_VALUE;
        long middle;
        while (left != right){
            middle = (left + right) / 2;
            if (test(middle, n) >= n){
                if (right != middle){
                    right = middle;
                }else {
                    right = middle - 1;
                }
            }else{
                if (left != middle){
                    left = middle;
                }else {
                    left = middle + 1;
                }
            }
        }
        System.out.println((left / 5) * 5);
    }

    /**
     * 测试
     * 求 i 的阶乘有多少个0
     * @param i 我
     * @return long
     */
    public static long test(long i, long n){
        int ans = 0;
        for (int j = 5; j <= i; j += 5) {
            int k = j;
            while (k % 5 == 0){
                ans++;
                k = k / 5;
                if(ans >= n){
                    return ans;
                }
            }
        }
        return ans;
    }
}

试题 F: 最大子矩阵

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 15
【问题描述】
小明有一个大小为 N × M 的矩阵,可以理解为一个 N M 列的二维数组。
我们定义一个矩阵 m 的稳定度 f ( m ) f ( m ) = max ( m ) min ( m ) ,其中 max ( m )
表示矩阵 m 中的最大值, min ( m ) 表示矩阵 m 中的最小值。现在小明想要从这
个矩阵中找到一个稳定度不大于 limit 的子矩阵,同时他还希望这个子矩阵的面
积越大越好(面积可以理解为矩阵中元素个数)。
子矩阵定义如下:从原矩阵中选择一组连续的行和一组连续的列,这些行
列交点上的元素组成的矩阵即为一个子矩阵。
【输入格式】
第一行输入两个整数 N M ,表示矩阵的大小。
接下来 N 行,每行输入 M 个整数,表示这个矩阵。
最后一行输入一个整数 limit ,表示限制。
【输出格式】
输出一个整数,分别表示小明选择的子矩阵的最大面积。
【样例输入】
3 4
2 0 7 9
0 6 9 7
8 4 6 4
8
【样例输出】
6
【样例说明】
满足稳定度不大于 8 的且面积最大的子矩阵总共有三个,他们的面积都是
6 (粗体表示子矩阵元素):
2 0 7 9
0 6 9 7
8 4 6 4
2 0 7 9
0 6 9 7
8 4 6 4
2 0 7 9
0 6 9 7
8 4 6 4
【评测用例规模与约定】
评测用例编号 N
M
1, 2
1 N 10 1 M 10
3, 4
N = 1
M 100000
5 12
1 N 10 M 10000
13 20
1 N 80 1 M 80
对于所有评测用例, 0 矩阵元素值 , limit 10 5
import java.util.Scanner;

/**
 * f最大子矩阵
 * 搜索剪枝
 * @author HP
 * @date 2022/04/29
 */
public class F_MaximumSubmatrix {
    static int row;
    static int line;
    static int limit;
    static int area = 0;
    static int[][] map;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        row = scanner.nextInt();
        line = scanner.nextInt();
        map = new int[row + 2][line + 2];
        for (int i = 1; i <= row ; i++) {
            for(int j = 1; j <= line; j++) {
              map[i][j] = scanner.nextInt();
            }
        }
        limit = scanner.nextInt();
        scanner.close();
        for(int row1 = 1; row1 <= row; row1++) {
          for(int line1 = 1; line1 <= line; line1++) {
            for(int row2 = row1; row2 <= row; row2++) {
              for(int line2 = line1; line2 <= line; line2++) {
                  int tempAare = (row2 - row1 + 1) * (line2 - line1 + 1);
                  if (tempAare > area){
                      Calculate(tempAare, row1, line1, row2, line2);
                  }
              }
            }
          }
        }
        System.out.println(area);
    }

    public static void Calculate(int tempArea, int row1, int line1, int row2, int line2){
        int max = 0;
        int min = Integer.MAX_VALUE;
        for(int i = row1; i <= row2; i++) {
          for(int j = line1; j <= line2; j++) {
            max = Math.max(max, map[i][j]);
            min = Math.min(min, map[i][j]);
          }
        }
        if ((max - min) <= limit){
            area = Math.max(area, tempArea);
        }
    }
}

试题 G: 数组切分

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 20
【问题描述】
已知一个长度为 N 的数组: A 1 , A 2 , A 3 , ... A N 恰好是 1 N 的一个排列。现
在要求你将 A 数组切分成若干个 ( 最少一个,最多 N ) 连续的子数组,并且
每个子数组中包含的整数恰好可以组成一段连续的自然数。
例如对于 A = { 1 , 3 , 2 , 4 } , 一共有 5 种切分方法:
{ 1 }{ 3 }{ 2 }{ 4 } :每个单独的数显然是 ( 长度为 1 ) 一段连续的自然数
{ 1 }{ 3 , 2 }{ 4 } { 3 , 2 } 包含 2 3 ,是 一段连续的自然数 ,另外 { 1 } { 4 } 显然
也是。
{ 1 }{ 3 , 2 , 4 } { 3 , 2 , 4 } 包含 2 4 ,是 一段连续的自然数 ,另外 { 1 } 显然也是。
{ 1 , 3 , 2 }{ 4 } { 1 , 3 , 2 } 包含 1 3 ,是 一段连续的自然数 ,另外 { 4 } 显然也是。
{ 1 , 3 , 2 , 4 } :只有一个子数组,包含 1 4 ,是 一段连续的自然数
【输入格式】
第一行包含一个整数 N 。第二行包含 N 个整数,代表 A 数组。
【输出格式】
输出一个整数表示答案。由于答案可能很大,所以输出其对 1000000007
模后的值
【样例输入】
4
1 3 2 4
【样例输出】
5
对于 30 % 评测用例, 1 N 20 .
对于 100 % 评测用例, 1 N 10000 .
import java.util.Scanner;

/**
 * g数组分割
 * 分割到最后一个数时进行判断
 * @author HP
 * @date 2022/04/29
 */
public class G_ArraySegmentation {
    static int length;
    static int ans = 0;
    static int[] list;
    static int[] segmentation;
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        length = scanner.nextInt();
        list = new int[length + 1];
        for(int i = 1; i <= length; i++) {
          list[i] = scanner.nextInt();
        }
        segmentation = new int[length + 1];
        segmentation[0] = 0;
        grouping(0);
        System.out.println(ans);
    }

    public static void grouping(int groupNumber){
        for (int i = segmentation[groupNumber] + 1; i <= length; i++) {
            segmentation[groupNumber + 1] = i;
            if (i == length){
                test(groupNumber + 1);
            }else{
                grouping(groupNumber + 1);
            }
        }
    }

    public static void test(int groupNumber){
        for (int i = 1; i <= groupNumber; i++) {
            int start = segmentation[i - 1];
            int end = segmentation[i];
            int max = Integer.MIN_VALUE;
            int min = Integer.MAX_VALUE;
            for (int j = start + 1; j <= end; j++) {
                max = Math.max(max, list[j]);
                min = Math.min(min, list[j]);
            }
            if ((max - min + 1) == (end - start)){
                continue;
            }else{
                return;
            }
        }
//        输出符合要求的分割
//        for (int i = 0; i <= groupNumber; i++) {
//            System.out.print(segmentation[i] + "\t");
//        }
//        System.out.println();
        ans++;
    }
}

试题 H: 回忆迷宫

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 20
【问题描述】
爱丽丝刚从一处地下迷宫中探险归来,你能根据她对于自己行动路径的回
忆,帮她画出迷宫地图吗?
迷宫地图是基于二维网格的。爱丽丝会告诉你一系列她在迷宫中的移动步
骤,每个移动步骤可能是上下左右四个方向中的一种,表示爱丽丝往这个方向
走了一格。你需要根据这些移动步骤给出一个迷宫地图,并满足以下条件:
1 、爱丽丝能在迷宫内的某个空地开始,顺利的走完她回忆的所有移动步
骤。
2 、迷宫内不存在爱丽丝没有走过的空地。
3 、迷宫是封闭的,即可通过墙分隔迷宫内与迷宫外。任意方向的无穷远处
视为迷宫外,所有不与迷宫外联通的空地都视为是迷宫内。(迷宫地图为四联
通,即只有上下左右视为联通)
4 、在满足前面三点的前提下,迷宫的墙的数量要尽可能少。
【输入格式】
第一行一个正整数 N ,表示爱丽丝回忆的步骤数量。
接下来一行 N 个英文字符,仅包含 UDLR 四种字符,分别表示上( Up )、
下( Down )、左( Left )、右( Right )。
【输出格式】
请通过字符画的形式输出迷宫地图。迷宫地图可能包含许多行,用字符 ‘*’
表示墙,用 ‘ ’ (空格)表示非墙。
你的输出需要保证以下条件:
1 、至少有一行第一个字符为 ‘*’
2 、第一行至少有一个字符为 ‘*’
3 、每一行的最后一个字符为 ‘*’
4 、最后一行至少有一个字符为 ‘*’
【样例输入】
17
UUUULLLLDDDDRRRRU
【样例输出】
*****
*
*
* *** *
* *** *
* *** *
*
*
*****
【样例说明】
爱丽丝可以把第六行第六个字符作为起点。
外墙墙墙墙墙外
墙内内内内内墙
墙内墙墙墙内墙
墙内墙墙墙内墙
墙内墙墙墙内墙
墙内内内内内墙
外墙墙墙墙墙外
【评测用例规模与约定】
对于所有数据, 0 < N 100 .
import java.util.Scanner;

/**
 * h记忆迷宫
 * 将路线周围设为墙
 * @author HP
 * @date 2022/04/29
 */
public class H_MemoryMaze {
    static int maxStep = 100;
    static int walkLange = 2 * maxStep + 1;
    static int[][] walkingMap = new int[walkLange + 1][walkLange + 1];
    static char[][] mazeMap = new  char[walkLange + 1][walkLange + 1];
    static int step;

    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        step = scanner.nextInt();
        scanner.nextLine();
        String string = scanner.nextLine();
        scanner.close();
        int x = maxStep + 1;
        int y = maxStep + 1;
        walkingMap[x][y] = 1;
        for (int i = 0; i < string.length(); i++) {
            char tempChar = string.charAt(i);
            if (tempChar == 'U'){
                x = x - 1;
            }else if (tempChar == 'D'){
                x = x + 1;
            }else if (tempChar == 'L'){
                y = y - 1;
            }else {
                y = y + 1;
            }
            System.out.println(x + " " + y);
            walkingMap[x][y] = 1;
        }
        int firstRow = 0;
        int lastRow = 0;
        int firstLine = 0;
        int lastLine = 0;
        for (int i = 1; i <= walkLange; i++) {
            for(int j = 1; j <= walkLange; j++) {
              if (walkingMap[i][j] == 1){
                  firstRow = i;
                  break;
              }
            }
            if (firstRow != 0){
                break;
            }
        }
        for (int i = walkLange; i >= 1; i--) {
            for(int j = 1; j <= walkLange; j++) {
                if (walkingMap[i][j] == 1){
                    lastRow = i;
                    break;
                }
            }
            if (lastRow != 0){
                break;
            }
        }
        for (int i = 1; i <= walkLange; i++) {
            for(int j = 1; j <= walkLange; j++) {
                if (walkingMap[j][i] == 1){
                    firstLine = i;
                    break;
                }
            }
            if (firstLine != 0){
                break;
            }
        }
        for (int i = walkLange; i >= 1; i--) {
            for(int j = 1; j <= walkLange; j++) {
                if (walkingMap[j][i] == 1){
                    lastLine = i;
                    break;
                }
            }
            if (lastLine != 0){
                break;
            }
        }
        for (int i = firstRow; i <= lastRow; i++) {
            for (int j = firstLine; j <= lastLine; j++) {
                if (walkingMap[i][j] == 1){
                    if (walkingMap[i - 1][j] != 1){
                        walkingMap[i - 1][j] = 2;
                    }
                    if (walkingMap[i + 1][j] != 1){
                        walkingMap[i + 1][j] = 2;
                    }
                    if (walkingMap[i][j - 1] != 1){
                        walkingMap[i][j - 1] = 2;
                    }
                    if (walkingMap[i][j + 1] != 1){
                        walkingMap[i][j + 1] = 2;
                    }
                }
            }
        }
        for (int i = firstRow; i <= lastRow; i++) {
            for (int j = firstLine; j <= lastLine; j++) {
                if(check(i, j)){
                    walkingMap[i][j] = 2;
                }
            }
        }
        for (int i = firstRow - 1; i <= lastRow + 1; i++) {
            for (int j = firstLine - 1; j <= lastLine + 1; j++) {
                if (walkingMap[i][j] == 2){
                    mazeMap[i][j] = '*';
                }else{
                    mazeMap[i][j] = ' ';
                }
            }
        }
        for (int i = firstRow - 1; i <= lastRow + 1; i++) {
            for (int j = firstLine - 1; j <= lastLine + 1; j++) {
                System.out.print(mazeMap[i][j]);
            }
            System.out.println();
        }
    }

    /**
     * 检查
     * 检查这个格子是否被墙围着, 且不是路线, 将这个格子设为墙
     * @param i 我
     * @param j j
     * @return boolean
     */
    public static boolean check(int i, int j){
        if (walkingMap[i][j] == 1){
            return false;
        }
        if (walkingMap[i][j] == 2){
            return true;
        }
        if(i == walkLange || i == 1 || j == walkLange || j == 1){
            return false;
        }
        return (check(i - 1, j) && check(i + 1, j) && check(i, j - 1) && check(i, j + 1));
    }
}

试题 I: 红绿灯

时间限制 : 1.0s
内存限制 : 512.0MB
本题总分: 25
【问题描述】
爱丽丝要开车去上班,上班的路上有许多红绿灯,这让爱丽丝很难过。为
了上班不迟到,她给自己的车安装了氮气喷射装置。现在她想知道自己上班最
短需要多少时间。
爱丽丝的车最高速度是
1
V
米每秒,并且经过改装后,可以瞬间加速到小于
等于最高速的任意速度,也可以瞬间停止。
爱丽丝家离公司有 N 米远,路上有 M 个红绿灯,第 i 个红绿灯位于离爱
丽丝家 A i 米远的位置,绿灯持续 B i 秒,红灯持续 C i 秒。在初始时(爱丽丝开
始计时的瞬间),所有红绿灯都恰好从红灯变为绿灯。如果爱丽丝在绿灯变红的
瞬间到达红绿灯,她会停下车等红灯,因为她是遵纪守法的好市民。
氮气喷射装置可以让爱丽丝的车瞬间加速到超光速(且不受相对论效应的
影响!),达到瞬移的效果,但是爱丽丝是遵纪守法的好市民,在每个红绿灯前
她都会停下氮气喷射,即使是绿灯,因为红绿灯处有斑马线,而使用氮气喷射
装置通过斑马线是违法的。此外,氮气喷射装置不能连续启动,需要一定时间
的冷却,表现为通过 K 个红绿灯后才能再次使用。(也就是说,如果 K = 1 ,就
能一直使用啦!)初始时,氮气喷射装置处于可用状态。
【输入格式】
第一行四个正整数 N M K V ,含义如题面所述。
接下来 M 行,每行三个正整数 A i B i C i ,含义如题面所述。
【输出格式】
输出一个正整数 T ,表示爱丽丝到达公司最短需要多少秒。
【样例输入】
90 2 2 2
30 20 20
60 20 20
【样例输出】
80
【样例说明】
爱丽丝在最开始直接使用氮气喷射装置瞬间到达第一个红绿灯,然后绿灯
通过,以最高速行进 60 秒后到达第二个红绿灯,此时绿灯刚好变红,于是她等
20 秒再次变为绿灯后通过该红绿灯,此时氮气喷射装置冷却完毕,爱丽丝再
次使用瞬间到达公司,总共用时 80 秒。
【评测用例规模与约定】
对于 30 % 的数据, N 100; M 10; M < K ; V = 1 .
对于 60 % 的数据, N 1000; M 100; K 50; B i , C i 100; V 10 .
对于 100 % 的数据, 0 < N 10 8 ; M 1000; K 1000; 0 < B i , C i 10 6 ; 0 <
V 10 6 ; 0 < A i < N ; 对任意 i < j , A i < A j .

试题 J: 拉箱子

时间限制 : 1.0s
内存限制 : 1.0GB
本题总分: 25
【问题描述】
推箱子是一款经典电子游戏,爱丽丝很喜欢玩,但是她有点玩腻了,现在
她想设计一款拉箱子游戏。
拉箱子游戏需要玩家在一个 N × M 的网格地图中,控制小人上下左右移动,
将箱子拉到终点以获得胜利。
现在爱丽丝想知道,在给定地形(即所有墙的位置)的情况下,有多少种
不同的可解的初始局面。
【初始局面】 的定义如下:
1 、初始局面由排列成 N × M 矩形网格状的各种元素组成,每个网格中有
且只有一种元素。可能的元素有:空地、墙、小人、箱子、终点。
2 、初始局面中有且只有一个小人。
3 、初始局面中有且只有一个箱子。
4 、初始局面中有且只有一个终点。
【可解】 的定义如下:
通过有限次数的移动小人(可以在移动的同时拉箱子),箱子能够到达终点
所在的网格。
【移动】 的定义如下:
在一次移动中,小人可以移动到相邻(上、下、左、右四种选项)的一个
网格中,前提是满足以下条件:
1 、小人永远不能移动到 N × M 的网格外部。
2 、小人永远不能移动到墙上或是箱子上。
3 、小人可以移动到空地或是终点上。
【拉箱子】 的定义如下:
在一次合法移动的同时,如果小人初始所在网格沿小人移动方向的反方向
上的相邻网格上恰好是箱子,小人可以拉动箱子一起移动,让箱子移动到小人
初始所在网格。
即使满足条件,小人也可以只移动而不拉箱子。
【输入格式】
第一行两个正整数 N M ,表示网格的大小。
接下来 N 行,每行 M 个由空格隔开的整数 0 1 描述给定的地形。其中
1 表示墙, 0 表示未知的元素,未知元素可能是小人或箱子或空地或终点,但不
能是墙。
【输出格式】
输出一个正整数,表示可解的初始局面数量。
【样例输入】
2 4
0 0 0 0
1 1 1 0
【样例输出】
13
【样例说明】
13 种可解的初始局面示意图如下:
人终箱空
墙墙墙空
********
人终空箱
墙墙墙空
********
人空终箱
墙墙墙空
********
箱人终空
墙墙墙空
********
空人终箱
墙墙墙空
********
箱终人空
墙墙墙空
********
空终人箱
墙墙墙空
********
箱终空人
墙墙墙空
********
箱空终人
墙墙墙空
********
空箱终人
墙墙墙空
********
箱终空空
墙墙墙人
********
箱空终空
墙墙墙人
********
空箱终空
墙墙墙人
【评测用例规模与约定】
对于 30 % 的数据, N , M 3 .
对于 100 % 的数据, 0 < N , M 10 .
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值