蓝桥2016-2022省赛B组第4题汇总讲解

总结:

2016:分小组 递归、全排列

2017:魔方状态

2018:测试次数 动态规划

2019:数的分解 字符串、思维分析

2020-1:分配口罩 深度优先遍历

2020-2:七段码 转二进制、字符串、深度优先遍历、思维分析

2021:货物摆放 数学思维

2022:最少刷题数 找规律、函数掌握

综上:

蓝桥杯第5题出题难的话会很难,不难的话也不简单(至少不能一眼看出答案)。这道题主要考察大家的思维分析和算法掌握能力了,从18年的动态规划就能看得出来。还有那么几个深度优先遍历的算法问题。

主要考察:
  1. 算法能力

递归、全排列、dfs、动态规划(如:2016、2018、2020-1、2020-2)

  1. 思维分析

判断条件如何设置能得到想要的结果(如2019、2020-2)

  1. 找规律

排序后的之间值是关键,每个都和这个中间数做比较(如2022)

  1. 字符串

数字转字符串、字符串转字符数组、字符转数字(如2019、2020-2)

接下来对2016-2022年第4题进行详细分析


2016年

9名运动员参加比赛,需要分3组进行预赛。有哪些分组的方案呢?

(代码填空题)

9名运动员参加比赛,需要分3组进行预赛。
有哪些分组的方案呢?
我们标记运动员为 A,B,C,… I
下面的程序列出了所有的分组方法。
该程序的正常输出为:
ABC DEF GHI
ABC DEG FHI
ABC DEH FGI
ABC DEI FGH
ABC DFG EHI
ABC DFH EGI
ABC DFI EGH
ABC DGH EFI
ABC DGI EFH
ABC DHI EFG
ABC EFG DHI
ABC EFH DGI
ABC EFI DGH
ABC EGH DFI
ABC EGI DFH
ABC EHI DFG
ABC FGH DEI
ABC FGI DEH
ABC FHI DEG
ABC GHI DEF
ABD CEF GHI
ABD CEG FHI
ABD CEH FGI
ABD CEI FGH
ABD CFG EHI
ABD CFH EGI
ABD CFI EGH
ABD CGH EFI
ABD CGI EFH
ABD CHI EFG
ABD EFG CHI
… (以下省略,总共560行)。
public class A
    {
        public static String remain(int[] a)
        {
            String s = "";
            for(int i=0; i<a.length; i++){//最后三个一组
                if(a[i] == 0) s += (char)(i+'A');
            }
            return s;
        }
    
        public static void f(String s, int[] a)
        {
            for(int i=0; i<a.length; i++){//确定第四个
                if(a[i]==1) continue;
                a[i] = 1;
                for(int j=i+1; j<a.length; j++){//确定第五个
                    if(a[j]==1) continue;
                    a[j]=1;
                    for(int k=j+1; k<a.length; k++){//确定第六个
                        if(a[k]==1) continue;
                        a[k]=1;
                        System.out.println(s+" "+(char)(i+'A')+(char)(j+'A')+(char)(k+'A')+" "+remain(a));  //填空位置
//                                                  ------------------------------------------------------
                         a[k]=0;
                     }
                     a[j]=0;
                 }
                 a[i] = 0;
             }
         }
     
         public static void main(String[] args)
         {
             int[] a = new int[9];
             a[0] = 1;//确定第一个人
     
             for(int b=1; b<a.length; b++){//确定第二个人
                 a[b] = 1;
                 for(int c=b+1; c<a.length; c++){//确定第三个人
                     a[c] = 1;
                      String s = "A" + (char)(b+'A') + (char)(c+'A');//保存前三个
                     f(s,a);//找后六个
                     a[c] = 0;
                 }
                 a[b] = 0;
             }
         }
     }

答案:(char)(i+'A')+(char)(j+'A')+(char)(k+'A')+" "+remain(a)

思路:结合上下文,理解代码,寻找突破点。

就比如,代码中有remain()方法但没有被引用的地方,就需要考虑这个方法在这里要被引用了。

主函数中将前三名队员确定且保存了,remain方法中也确定了三名队员并保存了,还有三名队员未保存,这里就要考虑这三名队员的存储情况。

2017年

魔方状态这道题有点难,我在网上也找了许多文章,要么大家也不会,要么代码含义太深我看不懂。

有兴趣的同学可以自己去搜一下,学习了解一下。我想,所有人都不会的题目如果你能做出来并掌握,那一定很骄傲很有成就感的吧。加油少年!

2018年

x星球的居民脾气不太好,但好在他们生气的时候唯一的异常举动是:摔手机。各大厂商也就纷纷推出各种耐摔型手机。x星球的质监局规定了手机必须经过耐摔测试,并且评定出一个耐摔指数来,之后才允许上市流通。x星球有很多高耸入云的高塔,刚好可以用来做耐摔测试。塔的每一层高度都是一样的,与地球上稍有不同的是,他们的第一层不是地面,而是相当于我们的2楼。

如果手机从第7层扔下去没摔坏,但第8层摔坏了,则手机耐摔指数n=7

特别地,如果手机从第1层扔下去就坏了,则耐摔指数n=0

如果到了塔的最高层第n层扔没摔坏,则耐摔指数为n

为了减少测试次数,从每个厂家抽样3部手机参加测试。某次测试的塔高为1000层,如果我们总是采用最佳策略,在最坏的运气下最多需要测试多少次才能确定手机的耐摔指数呢?请填写这个最多测试次数。

public static void main(String[] args){
    int[][] a=new int[1000+1][3+1];
    for(int i=1;i<=1000;i++)
        a[i][1]=i;//只有一部手机,最坏情况下有几层就需要几次测试

    for(int i=1;i<=3;i++)
        a[1][i]=1;//只有1层的话,无论几部手机只需要测试一次
    int min;
    for(int i=2;i<=1000;i++){//层数
        for(int j=2;j<=3;j++){//手机数
            min=Integer.MAX_VALUE;
            for(int k=1;k<=i;k++){//从第i层划分上下两部分,选出如果摔坏后从下层开始摔,和没摔坏从上层开始继续摔。这两种情况摔的次数最多的一个
                if(min>Math.max(a[k-1][j-1],a[i-k][j]))//k-1表示手机在这层坏了,i-k表示手机在这层没坏并且还需要测试i-k次
                    min=Math.max(a[k-1][j-1],a[i-k][j])+1;
            }
            a[i][j]=min;
        }
    }
    System.out.println(a[1000][3]);
}
答案:19

思路:这道题是动态规划问题。每一次的取值都要参考之前的取值。如果不能理解的同学可以先去了解一下动态规划原理或看一下背包问题。

给大家推荐两篇文章,帮助大家理解

推荐文章

https://blog.csdn.net/weixin_62636014/article/details/123389067

https://baijiahao.baidu.com/s?id=1597554648990612480&wfr=spider&for=pc

2019年

把 2019 分解成 3 个各不相同正整数之和,并且要求每个正整数都不包含数字 2 和 4,一共有多少种不同的分解方法?注意交换 3 个整数的顺序被视为同一种方法,例如 1000+1001+18 和 1001+1000+18 被视为同一种。

public static void main(String[] args){
    int count=0;
    for(int i=1;i<2019;i++){//A
       if(String.valueOf(i).indexOf("2")!=-1||String.valueOf(i).indexOf("4")!=-1)//valueOf将转字符串,indexOf判断字符是否在数组中,如果在则返回下表,不在则返回-1
           continue;
           for(int j=i+1;j<2019;j++){//B
               if(String.valueOf(j).indexOf("2")!=-1||String.valueOf(j).indexOf("4")!=-1)
                   continue;
                   int k=2019-i-j;//C
                   if(i==j||i==k||j==k)//排除AAB,AAA类可能性
                       continue;
               if(k>0&&String.valueOf(k).indexOf("2")==-1&&String.valueOf(k).indexOf("4")==-1)
                   count++;
               }

    }
    System.out.println(count/3);
}
答案:40785

思路:对三个数分别进行'2'、'4'排除,得到的数再进行求和判断,如果之和为2019则计数。人为规定A<=B<=C,在排除重复(类似AAB、AAA)情况下求解。

2020年-1

【问题描述】
某市市长获得了若干批口罩,每一批口罩的数目如下:
(如果你把以下文 字复制到文本文件中,请务必检查复制的内容是否与文档中的一致。
在试题目 录下有一个文件 mask.txt,内容与下面的文本相同) 
9090400 
8499400 
5926800 
8547000 
4958200 
4422600 
5751200 
4175600 
6309600 
5865200 
6604400 
4635000 
10663400 
8087200 
4554000 

现在市长要把口罩分配给市内的 2 所医院。
由于物流限制,每一批口罩只能全部分配给其中一家医院。
市长希望 2 所医院获得的口罩总数之差越小越好。 
请你计算这个差最小是多少?

【答案提交】
这是一道结果填空题,你只需要算出结果后提交即可。
本题的结果为一个整数,在提交答案时只填写这个整数,填写多余的内容将无法得分。
 static long cha=Long.MAX_VALUE;
    static long[] a={
            9090400, 8499400, 5926800, 8547000, 4958200,
            4422600, 5751200, 4175600, 6309600, 5865200,
            6604400, 4635000, 10663400, 8087200, 4554000
    };
public static void main(String[] args){
    dfs(0,0,0);
    System.out.println(cha);
}
public static void dfs(int k,long num1,long num2){
    if(k==15){//递归完每个数后求两个医院的差值并记录最小差值
        if(cha>Math.abs(num1-num2))
            cha=Math.abs(num1-num2);
        return;
    }
    dfs(k+1,num1+a[k],num2);//分给1号医院
    dfs(k+1,num1,num2+a[k]);//分给2号医院
}
答案:2400

思路:通过dfs遍历所有可能结果,并求得最小查即最优解。

2020年-2

小蓝要用七段码数码管来表示一种特殊的文字。

上图给出了七段码数码管的一个图示,数码管中一共有 7 段可以发光的二

极管,分别标记为 a, b, c, d, e, f, g。

小蓝要选择一部分二极管(至少要有一个发光来表达字符。在设计字符

的表达时,要求所有发光的二极管是连成一片的。

例如:b 发光,其他二极管不发光可以用来表达一种字符。

例如:c 发光,其他二极管不发光可以用来表达一种字符。这种方案与上

一行的方案可以用来表示不同的字符,尽管看上去比较相似。

例如:a, b, c, d, e 发光,f, g 不发光可以用来表达一种字符。

例如:b, f 发光,其他二极管不发光则不能用来表达一种字符,因为发光

二极管没有连成一片

请问,小蓝可以用七段码数码管表达多少种不同的字符?

static int count=0;
    static int[][] m= {
            {0,1,0,0,0,1,0},
            {1,0,1,0,0,0,1},
            {0,1,0,1,0,0,1},
            {0,0,1,0,1,0,0},
            {0,0,0,1,0,1,1},
            {1,0,0,0,1,0,1},
            {0,1,1,0,1,1,0}
    };
    static char[] a;
    static boolean flag;
    public static void main(String[] args) {

        for (int j = 1; j < 128; j++) {//对127中可能值进行循环查找
            // 获取128个数的二进制,并取反(a[0]表示灯管1,以此类推a[6]表示灯管7)
            StringBuffer s=new StringBuffer(Integer.toBinaryString(j)).reverse();
            a=s.toString().toCharArray();//将二进制数转为字符数组
            int[] f={1,1,1,1,1,1,1};
            flag=true;
            for(int i=0;i<a.length;i++){
                f[i]=0;//未亮灯且标记为被遍历过
                if(a[i]=='1')
                {
                    dfs(f,i);//从1号管开始找到第一个亮灯的管
                    break;
                }
            }
            if(flag==false)count++;//符合要求则计数
        }
        System.out.println(count);
    }
    public static void dfs(int[] f,int k){//k表示亮灯的灯管序号
        f[k]=0;//标记为遍历过
        for(int i=0;i<a.length;i++){
            if(m[k][i]==1&&a[i]=='1'){//连通且亮着
                if(f[i]==1)//未被遍历过
                    dfs(f,i);//寻找下一个
            }
        }
        for(int i=0;i<a.length;i++){//存在未被连通的,即无法连通的
            if(f[i]==1&&a[i]!='0')//存在亮灯但不连通的灯管
                return;//退出该层递归
        }
        flag=false;//每个灯管被遍历且亮灯的灯管是连通的
        return;
    }
}
答案:80

思路:通过dfs遍历所有情况同时判断是否连通和是否亮灯,是则做标记,如果7个灯都被遍历完且符合要求则计数。

具体详解看这里:七段码

2021年

小蓝有一个超大的仓库,可以摆放很多货物。现在,小蓝有n 箱货物要摆放在仓库,每箱货物都是规则的正方体。小蓝规定了长、宽、高三个互相垂直的方向,每箱货物的边都必须严格平行于长、宽、高。小蓝希望所有的货物最终摆成一个大的立方体。即在长、宽、高的方向上分别堆L、W、H 的货物,满足n = L × W × H。给定n,请问有多少种堆放货物的方案满足要求。

例如,当n = 4 时,有以下6 种方案:1×1×4、1×2×2、1×4×1、2×1×2、2×2×1、4×1×1。

请问,当n = 2021041820210418 (注意有16 位数字)时,总共有多少种方案?提示:建议使用计算机编程解决问题。

public static void main(String[] args) {
        long n=2021041820210418l;
        int count=0;
        List<Long> list = new ArrayList<>();
        for(long i=1;i<=Math.sqrt(n);i++){//求n的所有因子
            if(n%i==0)
            {
                list.add(i);
                list.add(n/i);
            }
        }
        for(int i=0;i<list.size();i++){//从这些因子中寻找符合要求的
            for(int j=0;j<list.size();j++){
                for(int k=0;k<list.size();k++){
                    if(list.get(i)*list.get(j)*list.get(k)==n)count++;
                }
            }
        }
        System.out.println(count);
    }
答案:2430

思路:由于n数值太大,如果直接三层for循环的话耗时太大。可以从题目示例找突破口。

n=L*W*H。也就是求L、W、H的不同组合。而L、W、H又都是n的因子。所有计算过程就转换为求n的三个乘积为n的不同因子有多少种组合方式

步骤:

先求出n的所有因子,并将其存入列表

对列表中的因子逐个循环,找出乘积为n的三个因子并计数+1

2022年

小蓝老师教的编程课有 N 名学生,编号依次是 1 . . . N第 i 号学生这学期刷题数量Ai。对于每一名学生,请你计算他至少还要再刷多少道题,才能使得全班刷题比他多的学生数不超过刷题比他少的学生数。

public static void main(String[] args) {
        Scanner input=new Scanner(System.in);
        int n=input.nextInt();//输入n
        int[] a=new int[n];//输入n位同学的刷题数
        int[] temp = new int[n];//临时数组,其值等于数组a
        int[] b=new int[n];//存每位同学还要刷题数
        int mid;//中间值
        for(int i=0;i<n;i++){//输入刷题数
            a[i]=temp[i]=input.nextInt();
        }
        Arrays.sort(temp);//对临时数组进行升序排序
        if(temp.length%2==0)//获取中间值
            mid=temp.length/2+1;
        else mid=temp.length/2;
        for(int i=0;i<n;i++){//遍历每位同学的刷题数求其还需要再刷多少题
            if(a[i]<temp[mid])b[i]=temp[mid]-a[i]+1;
        }
        for(int i=0;i<n;i++){//输出结果列表
            System.out.printf("%d",b[i]);
        }
    }
例如:

输入n: 5

输入Ai:12 10 15 20 6

输出:03007

思路:输入n个学生的刷题数,对刷题数量进行升序排序,找到中间值。对输入的每个学生刷题数与中间值进行比较,小于则求出差值并加1,使其大于中间值。大于则为0。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值