海盗分酒
题目描述:
有一群海盗(不多于 20 人),在船上比拼酒量。过程如下:打开一瓶酒,所有在场的人平分喝下,有几个人倒下了。再打开一瓶酒平分,又有倒下的,再次重复 ...... 直到开了第 4 瓶酒,坐着的已经所剩无几,海盗船长也在其中。当第 4 瓶酒平分喝下后,大家都倒下了。等船长醒来,发现海盗船搁浅了。他在航海日志中写到:“ ...... 昨天,我正好喝了一瓶 ....... 奉劝大家,开船不喝酒,喝酒别开船 ......”
请你根据这些信息,推断开始有多少人,每一轮喝下来还剩多少人。
如果有多个可能的答案,请列出所有答案,每个答案占一行。
格式是:人数 , 人数 ,...
方法一:枚举法
思想:假设第一瓶酒a个人喝,第二瓶酒b个人喝,第三瓶酒c个人喝 ,第四瓶酒d个人喝,因为船长喝了一瓶,因为船长最后总共喝了1瓶
所以有1/a+1/b+1/c+1/d=1同时a>b>c>d
//海盗分酒
public class HaiDaoFenJiu {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
/*for循环实现*/
for(int a=20;a>4;a--)
{
for(int b=a-1;b>3;b--)
{
for(int c=b-1;c>2;c--)
{
for(int d=c-1;d>1;d--)
{
//下面的判断最好通分,不要用浮点数来求,那样会出现误差
//abs(1.0/a+1.0/b+1.0/c+1.0/d-1.0)<1e-8条件如果是这样的话,误差可能会小点
if(b*c*d+a*c*d+a*b*d+a*b*c==a*b*c*d)
System.out.println(a+" "+b+" "+c+" "+d);
}
}
}
}
}
}
方法二:递归实现for循环,递归函数是第几次喝酒的最多人数是m
public class HaiDaoFenJiu {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a=new int[4];//保存a,b,c.d的值
f(a,1,20);
}
//第index喝酒时最多的人数是m
public static void f(int[] a,int index,int m)
{
if(index==4)
{
for(int i=m;i>1;i--)
{
a[index-1]=i;
if(a[1]*a[2]*a[3]+a[0]*a[2]*a[3]+a[0]*a[1]*a[3]+a[1]*a[2]*a[0]==a[0]*a[1]*a[2]*a[3])
{
System.out.println(a[0]+" "+a[1]+" "+a[2]+" "+a[3]);
}
}
}
else
{
if(m<=1)
{
//System.out.println("a");
return;
}
else
{
for(int j=m;j>1;j--)
{
a[index-1]=j;
//System.out.println(j);
f(a,index+1,j-1);
}
}
}
}
}
方法三:另一种递归代替for循环的方法
又是一个递归的题目,这次的是比较简单了,但是还是要细心和注意一点技巧
这个题目简单就简单在人数不会超过20还有次数确定只有四次
还有就是老大最后才倒下,有这几个条件那么就简单了!
直接用递归来搞定,
int find_ans(int rec,int now,int son,int mother)
rec来记录次数,now来表示现在还剩下多少人,son分子,mother分母
这样只要满足son==mother还有rec==4就输出这一组结果就完事了
我的写法注定是从大到小不会不符合逻辑的!
package lilu.shuxue;
public class HaiDaoFenJiu2 {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] a=new int[4];//保存a,b,c.d的值
for(int i=1;i<=20;i++)
{
a[0]=i;
f(a,1,i-1,1,i);
}
}
//rec来记录次数,now来表示现在还剩下多少人,son分子,mother分母
public static void f(int[] a,int rec,int now,int son,int mother)
{
if(rec>4)
return;
if(rec==4)
{
if(son==mother)
{
System.out.println(a[0]+" "+a[1]+" "+a[2]+" "+a[3]);
}
}
else
{
for(int i=now;i>0;i--)
{
a[rec]=i;
f(a,rec+1,i-1,son*i+mother,mother*i);
}
}
}
}
方法二的递归和方法二的递归的不同之处就是方法二是在最后计算是否相等,方法三是在递归的过程中直接计算。