您的位置:首页 > 其它

猜生日算法

2013-11-13 12:46 357 查看
通过询问对方5个问题,每个问题均是提问其生日在不在给出的集合中,如果是则输入1,不是输入0,那么在5个回合后,程序将给出这个人生日为几号。


参考《Introduction to Java Programming 8th》,在最后面写出了原理的实现,下面是代码。

import java.util.Scanner;

public class Item_001
{
/**
* 通过询问某个人5个问题,找出其出生日期
*/
public static void main(String[] args)
{
//给定5个集合
String gather1 = "",gather2="",gather3="",gather4="",gather5="";
for(int i = 1;i<=31;i++)
{
String iBin = Long.toBinaryString(i);
int len = iBin.length();
if(len<5)for(int j =0;j<5-len;j++)iBin="0"+iBin;//统一的输出5位数,位数不够则左边用0补齐
//System.out.printf("%-2d----%5s\n",i,iBin);//debug
for(int k=0;k<5;k++)//确定第几位是1,然后放入对应的集合中
{
int isOne = Integer.parseInt(iBin.substring(k, k+1));
if(isOne==1)
switch (k)
{
case 4:
gather1 = gather1 +"	"+ Integer.parseInt(iBin,2);//中间的空格需要用tab来空出
break;
case 3:
gather2 = gather2 + "	"+Integer.parseInt(iBin,2);
break;
case 2:
gather3 = gather3 + "	"+Integer.parseInt(iBin,2);
break;
case 1:
gather4 = gather4 +"	"+ Integer.parseInt(iBin,2);
break;
case 0:
gather5 = gather5 + "	"+Integer.parseInt(iBin,2);
break;
}
}
}
int day = 0;
Scanner sc = new Scanner(System.in);
FormatOutput(gather1);
int answer = sc.nextInt();
if(answer == 1) day+=1;
FormatOutput(gather2);
answer = sc.nextInt();
if(answer == 1) day+=2;
FormatOutput(gather3);
answer = sc.nextInt();
if(answer == 1) day+=4;
FormatOutput(gather4);
answer = sc.nextInt();
if(answer == 1) day+=8;
FormatOutput(gather5);
answer = sc.nextInt();
if(answer == 1) day+=16;
System.out.println("\nYour birthday is "+day+"!");
sc.close();
}
public static void FormatOutput(String str)
{
System.out.println("Is your birthday in this set?");
String arr[] = str.split("	");
for(int m=1;m<arr.length;m++)
{
System.out.print(arr[m]+"	");
if(m%4==0)System.out.println('\n');;
}
System.out.println("\nEnter 0 for NO and 1 for Yes:");
System.out.println();
}

}
/*
* 关于猜生日的一些说明:
* 一个人的生日只能是[1,31]号中的某一天,31的二进制位11111=00001+00010+00100+01000+10000,也就是:
* 		00001--------------1
* 		00010--------------2
* 		00100--------------4
* 		01000--------------8
* 	+	10000--------------16
* ————————————————————————————
*      11111--------------31
* 然而我们知道,二进制只能由0或者1组成,所以一个数字[1,31]的各个位数只能是0或者1,所以由上面的数组合可以组合相加,可以得到任意一个数字。
* 这样的话,我们任意取一个数字,其二进制表示为:abcde(注:分别为各个位上的数字,比如10110,则a=1,b=0,c=1,d=1,e=0),
* 则abcde可以由如下算式得到:
* 		0000e
* 		000d0
* 		00c00
* 		0b000
* 	 +	a0000
* ————————————————————————————
* 		abcde
* 显然这个abcde是任意的,并且a,b,c,d或者e要么为0要么为1。这样我们可以将一个数[1,31]放在5个集合的某个集合中,
* 规则是:
* 如果这个数的e=1(不限定其他位数字),那么就应该放在集合set1中。
* 如果这个数的d=1(不限定其他位数字),那么就应该放在集合set2中。
* 如果这个数的c=1(不限定其他位数字),那么就应该放在集合set3中。
* 如果这个数的b=1(不限定其他位数字),那么就应该放在集合set4中。
* 如果这个数的a=1(不限定其他位数字),那么就应该放在集合set5中。
* 注:显然可能一个数字放在多个集合中。
* 当将这些数放置在不同的集合中后,通过指定某个数存在于5个集合中的哪些集合。我们便可以轻易的得到这个数字。
* 举个例子来说,比如23,其二进制为10111,那么我们会将它放置到set1,set2,set3,set5中。
* 这样当你指定说某个数在集合set1,set2,set3,set5,那么我们便知道,你说的某数必然是a=1,b=0,c=1,d=1,e=1.
* 很容易的我们便可以猜出你说的某数为16+4+2+1=23。
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: