第七届 蓝桥杯决赛 Java B组 打靶 解题报告(DFS,回溯,全排列)

来源:互联网 发布:java电梯项目经理 编辑:程序博客网 时间:2024/04/29 05:59

题目:

打靶

小明参加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<da.length; i++){for(int j=0; j<da[i]; j++) System.out.print(ta[i] + " ");}System.out.println();return;}for(int i=0; i<=bu; i++){da[k] = i;f(ta, da, k+1,  __________________ , bu-i, sc-ta[k]*i);   // 填空位置}da[k] = 0;}public static void main(String[] args){int[] ta = {1,2,3,5,10,20,25,50};int[] da = new int[8];f(ta, da, 0, 3, 6, 96);}}
注意:只填写划线处缺少的内容,不要填写已有的代码或符号,也不要填写任何解释说明文字等。


本题结论有待验证,证明后更改,主要纠结于3代表总共三个弹孔,还是三次重复穿过弹孔

如果代表总共三个弹孔  答案:i > 0  ? ho - 1: ho

如果代表总共三次重复穿过:答案:i > 1 ? ho - (i - 1) : ho

分析:

1.main函数分析:

public static void main(String[] args) {int[] ta = { 1, 2, 3, 5, 10, 20, 25, 50 };//记录分值int[] da = new int[8];//记录每个分值的个数//// f(ta, da, k,ho,bu, sc);f(ta, da, 0, 3, 6, 96);//第一二个参数不用解释,从ta第0位开始枚举,3个重复弹孔,上限6个分数,共96分}

2.递归函数分析:

static void f(int[] ta, int[] da, int k, int ho, int bu, int sc) {if (ho < 0 || bu < 0 || sc < 0)//最后ho bu sc 都大于0 才有递归的必要(剪枝) return;if (k == ta.length) {// 当k枚举完ta数组(类似for循环的i),开始判断if (ho > 0 || bu > 0 || sc > 0)// 三个参数都等于0,说明递归过程会把已经枚举的值扣除相应的ho,bu,sc值return;for (int i = 0; i < da.length; i++) {//输出每个分值for (int j = 0; j < da[i]; j++)System.out.print(ta[i] + " ");}System.out.println();return;}for (int i = 0; i <= bu; i++) {//bu是分数个数的上限da[k] = i;//每一个分值从0~bu(即6)进行深搜枚举f(ta, da, k + 1, i > 1 ? ho - (i - 1) : ho, bu - i, sc - ta[k] * i); // 填空位置}/*刚开始直接填0,发现每个答案加起来就是96,唯一不同的就是,有的弹孔数不是3个 *可见,ho的值就是用来筛选的且要扣除有几个重复的,由da数组可知每个分值是记录每个分值个数的 *所以我推出ho,当分值的个数大于1,只要减去每个分值的个数扣掉1之后的值(即重复的数量),如da[1] = 3,那么我就ho扣掉2 *最后运行,果然,得出了三组数据且只有三个弹孔,完美解决 * */da[k] = 0;//分值每种情况枚举完之后要回溯,清零}

把ho填0,得出的结果:


推出代码后结果:


所以应该填入: i > 1 ? ho - (i - 1) : ho

完整代码:

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 < da.length; i++) {for (int j = 0; j < da[i]; j++)System.out.print(ta[i] + " ");}System.out.println();return;}for (int i = 0; i <= bu; i++) {da[k] = i;f(ta, da, k + 1, i > 1 ? ho - (i - 1) : ho, bu - i, sc - ta[k] * i); // 填空位置}da[k] = 0;}public static void main(String[] args) {int[] ta = { 1, 2, 3, 5, 10, 20, 25, 50 };int[] da = new int[8];//// f(ta, da, k,ho,bu, sc);f(ta, da, 0, 3, 6, 96);}}


总结:

主要还是考深搜还有回溯,跟全排列有点像,类似全排列的进阶

















0 0