海盗分酒(数学问题)

海盗分酒

题目描述:

有一群海盗(不多于 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);
                }
            }
        }

}
方法二的递归和方法二的递归的不同之处就是方法二是在最后计算是否相等,方法三是在递归的过程中直接计算。



  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值