打靶蓝桥杯-2016年java-B组决赛

时间:2022-09-10 16:32:38

题目描述

打靶

小明参加X星球的打靶比赛。
比赛使用电子感应计分系统。其中有一局,小明得了96分。

这局小明共打了6发子弹,没有脱靶。
但望远镜看过去,只有3个弹孔。
显然,有些子弹准确地穿过了前边的弹孔。

不同环数得分是这样设置的:
1,2,3,5,10,20,25,50

那么小明的6发子弹得分都是多少呢?有哪些可能情况呢?

下面的程序解决了这个问题。
仔细阅读分析代码,填写划线部分缺失的内容。

public class Main
{
static void f(int[] ta, int[] da, int k, int ho, int bu, int sc)
{
if(ho<0 || bu<0 || sc<0) return;
if(k==ta.length){
if(ho>0 || bu>0 || sc>0) return;
for(int i=0; i

答案 ho - (i == 0 ? 0 : 1)

分析说明

对于代码填空题我的分析一般就是通过凑的方式来解题,因为一般解题的框架都出来了此时你只需要根据解题的描述进一步填空就行了。
对于本题来说主要就在于对每个参数的分析,
f(ta, da, 0, 3, 6, 96);
这一句话几乎把所有的关键内容都给解释了ta与da通过上面的定义可以看出ta为

不同环数得分是这样设置的:1,2,3,5,10,20,25,50

然后通过

    for(int j=0; j<da[i]; j++) 

并且在加上da的长度

int[] da = new int[8];

便可以推测出来da存储的为每个分数出现的次数

如果有dfs全排列的基础的话,可以很容易看出来k代表当前位置,相当于一个游标,对于ho刚开始可能不容易看出来,因为它也是将来填空要填的内容,所以可以先忽略。
然后看bu,通过上一部分析得出的da存储的为每个分数出现的次数,并且bu的初始值为6在与题干比较

这局小明共打了6发子弹

推断出了bu是剩下的子弹数
同理sc的初值为96很容易看出sc代表分数。


分析完关键变量后下一步主要就是简单分析代码,不需要读懂,但要基本明白其所讲内容,通过一个数组并且加递归,可以看出其主要运用的就是全排列的思想,把每个环所有可能的次数都过滤一遍,并且保留下来的都是刚好bu==0 ho==0 sc==0的

if (ho < 0 || bu < 0 || sc < 0)
return;

if (ho > 0 || bu > 0 || sc > 0)
return;

所以便推断出ho一定是向下减少的,并且最终减为0,而且ho的初值为3,与题干中的只有3个弹孔刚好重和,所以ho代表的就是剩下的弹孔数,而这个弹孔数其实就是da中不为0的数的个数
比如da中存储的为0 0 2 0 0 2 2 0
则其不为0的为三个刚刚好,所以关键在于怎么看da中不为0的,因为代码只能填一个空,所以不能进行遍历,所以可以采用边进行边统计的方法,因为是看da是否为0为0则所以有
打靶蓝桥杯-2016年java-B组决赛

此时可以增加一行测试代码

for (int i = 0; i <= bu; i++) {
int t;
da[k] = i;
if (i == 0)//i与da一样的
t = 0;
else
t = 1;
f(ta, da, k + 1, ho - t, bu - i, sc - ta[k] * i); // 填空位置
}

通过测试看出输出结果为正确的,所以便可以确定前面的推论正确,此时需要的就是将代码减为一行。
这个我想难不倒大家,一个三目运算符搞定。

    f(ta, da, k + 1, ho - (i == 0 ? 0 : 1), bu - i, sc - ta[k] * i); // 填空位置

至于详细分析有兴趣的话可以进行一下。