前两天上课,车老师留了个课后作业,想考察一下我们还剩下多少Java水平。具体要求是将1000个鸡蛋分到10个箱子里,实现随机输入一个1000及以内的数字,都可以用这十个箱子来表示。一年多没碰过Java的我当时还没意识到问题的严重性,回到宿舍想破头也没想出来如何实现。后来实在没办法了,查了一下,才得知考查的是二进制,实在惭愧。我把参考的文章放在下面:1000个苹果,放到10个框里,怎么样保证任意数量的苹果都可以被表示出来
接下来我就拾人牙慧,复述一下算法思想。
1000是接近1024的数字,1024也就是2的10次方。那么用2的i次方(0<=i<10)依次装十个箱子,就可以表述1024以内所有的数字(因为1023转换为二进制是1111111111)。于是我们从小到大开始装箱子:
箱子编号 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 |
鸡蛋数目 | 1 | 2 | 4 | 8 | 16 | 32 | 64 | 128 | 256 | 489 |
因为装到第十个箱子时,前面已经装了511个鸡蛋了,那第10个箱子只能装1000-511=489个鸡蛋了。接下来我们要做的就是把用户给出的数字转换为二进制, 然后每一位对应上述编号的箱子,例如第一位就对应第一个箱子...,以此类推。
假如用户给出了数字13,转换为二进制就是 0000001101 ,那么我们只需要取出第一、三、四个箱子即可,结果是1+4+8=13。看似很完美对吗,但其实有一个大问题,就是我们第十个箱子本应该放512个鸡蛋,但最终因为数量不够放了489个鸡蛋,那么只要用户给出的数字大于等于512,转换为二进制后,第十位必然是1,本来我们要用第十个箱子里的512个鸡蛋,但现在只有489个了,差了23个,怎么办?
解决方法就是在用户输入数据后,自己先判断一下是不是小于512,如果小于512,那我们什么也不用变,因为用不到第十个箱子;如果大于512,那我们就人为把第十个箱子先取出来,默认已经使用第十个箱子了,然后把用户给出的数据-489,剩下的鸡蛋数再让他转换为二进制,剩下的就跟上面一样了。
那么基本算法思想已经叙述完了,具体就是程序实现了。由于也是初学者,代码水平实在一般,若有大佬不吝赐教,实在感激。
import java.util.*;
/*1000个鸡蛋,一次性放入10个箱子中,放好后数量不能改变
要求:在1000以内随便报一个数,得出搬哪几个箱子即可完成*/
public class EggAssignment {
public static void splitLine() {
System.out.println("—————————————————————————————————————————————————————————————————————————————————");
}
public static void main(String[] args) {
//生成存放鸡蛋的十个盒子
int[] eggBox = new int[10];
//生成存放转化为二进制的数字
int[] key_2 = new int[10];
//生成scanner对象sc用以接收键盘输入
Scanner sc = new Scanner(System.in);
/*key用来接收键盘输入,sum用以累加计算取出鸡蛋的总数
jugde用于判断是否让用户继续输入*/
int key=0,sum=0;
boolean jugde = true;
//初始化数组末尾(第10个箱子)
eggBox[eggBox.length-1] = 489;
//用二进制初始化数组(前9个箱子)
for (int i = 0; i < 9 ; i++) {
eggBox[i] = (int) Math.pow(2, i);
}
//输出箱子里放鸡蛋的数目
splitLine();
for (int i = 0; i < eggBox.length; i++) {
System.out.print("第"+(i+1)+"个箱子\t");
}
System.out.println();
splitLine();
for (int i = 0; i < eggBox.length; i++) {
System.out.print(eggBox[i]+"个\t");
}
System.out.println();
splitLine();
/*用户交互 while循环限定用户只能输入1000及以内的数据
bug:输入非整型数据会报异常
处理:使用try-catch抓取异常 令用户重新回到循环输入正确数据*/
System.out.print("请输入1000以内的整数:");
while(jugde) {
try {
key = sc.nextInt();
while(key>1000) {
splitLine();
System.out.println("输入有误,请重新输入");
System.out.print("请输入1000以内的整数:");
key = sc.nextInt();
}
jugde = false;
} catch (InputMismatchException e) {
splitLine();
System.out.println("输入有误 请勿输入大于1000的整数及非整数!");
System.out.print("请重新输入1000以内的整数:");
sc = new Scanner(System.in);
}
}
//释放Scanner类对象sc调用的资源
sc.close();
//除二取余法将十进制转化为二进制
//分两种情况,小于512则直接取出盒子 大于512默认先取出第十个盒子 剩下的拿前9个盒子表示
//小于512直接转换二进制 大于512先减去489再转换二进制
if(key<512) {
for (int i = 0; i < 10 ;i++) {
key_2[i]=key%2;
key=key/2;
}
}else {
key=key-489;
for (int i = 0; i < 9 ;i++) {
key_2[i]=key%2;
key=key/2;
}
key_2[9]=1;//默认第十个箱子被取出
}
//将二进制数组下标为1时 取出对应盒子的鸡蛋
System.out.print("共");
for (int i = 0; i < 10; i++) {
if(key_2[i]==1) {
System.out.print("第"+(i+1)+"个箱子 ");
sum = sum + eggBox[i];
}
}
System.out.println("被取出");
System.out.println("成功取出了 "+sum+" 个鸡蛋!");
}
}
程序运行结果如下:
再次感谢-Mei-的文章,给我了很大启发,不然现在还看不懂问题要求,十分感激!