关于海盗喝酒的问题

昨天做了一个海岛喝酒的问题,让我今天一天都没安生,这是我学c语言这么久以来最恶心的情况,我将其称之为潘多拉之谜。太邪性,到现在我还是不懂其中的奥妙所在。废话不多说,题如下:
拼酒量

有一群海盗(不多于20人),在船上比拼酒量。过程如下:打开一瓶酒,
所有在场的人平分喝下,有几个人倒下了。再打开一瓶酒平分,又有倒下的,
再次重复…… 直到开了第4瓶酒,坐着的已经所剩无几,海盗船长也在其中。
当第4瓶酒平分喝下后,大家都倒下了。 等船长醒来,发现海盗船搁浅了。
他在航海日志中写到:“……昨天,我正好喝了一瓶…….奉劝大家,开船不喝酒,喝酒别开船……”
请你根据这些信息,推断开始有多少人,每一轮喝下来还剩多少人。
如果有多个可能的答案,请列出所有答案,每个答案占一行。
格式是:人数,人数,…
例如,有一种可能是:20,5,4,2,0*/
先列出正确的代码方便陈述我的问题:

#include <stdio.h>
int main(int argc, const char * argv[])//主函数
{
    int i=0,j=0,k=0,l=0,m=0,s=0;//m为最后一次剩余的人数,i为最后一次分酒的人数,j为倒数第二次分酒的人数,k为倒数第三次分酒的人数,l为第一次分酒的人数
    for (i=2; i<4; i++)//逻辑推断最后一次分酒人数最少2人,分酒四次,所以人数最多不到4人
    {
        for (j=i+1; j<6; j++)//逻辑推断,倒数第二次分酒人数比倒数第一次人数至少多1人,假设最后一次分酒每人分到了最多的量1/2,则这次分酒人数最多不到6人
        {
            for (k=j+1; k<12; k++)//逻辑推断,倒数第三次分酒人数比倒数第二次人数至少多1人,假设最后一次分酒每人分到了最多的量1/2,倒数第二次分酒每人分到了最多的量1/3,则这次分酒人数最多不到12人
            {
                for (l=k+1; l<21; l++)//根据题意,初始分酒人数最多不到21人
                {
                    s=i*j*k*l;//1/i+1/j+1/k+1/l=1时,令s=i*j*k*l,则s/i+s/j+s/k+s/l==s
                    if (s/i+s/j+s/k+s/l==s)//判断船长喝的酒够不够一瓶
                    {
                        printf("%d,%d,%d,%d,%d\n",l,k,j,i,m);//按照样例输出
                    }
                }
            }
        }
    }
    return 0;//返回0
}

看着这道题凭白无奇,答案为:
18,9,3,2,0
15,10,3,2,0
20,5,4,2,0
12,6,4,2,0
然而其中却暗藏玄机,经过多方证明,我一下陈述的问题和编译器无关。
起初,我的代码并不是这样的,而是一个更加直观的(最中间的判断语句是比较直接点),代码如下:

#include <stdio.h>

int main(int argc, const char * argv[])//主函数
{
    float i=0,j=0,k=0,l=0,m=0;//m为最后一次剩余的人数,i为最后一次分酒的人数,j为倒数第二次分酒的人数,k为倒数第三次分酒的人数,l为第一次分酒的人数
    for (i=2; i<4; i++)//逻辑推断最后一次分酒人数最少2人,分酒四次,所以人数最多不到4人
    {
        for (j=i+1; j<6; j++)//逻辑推断,倒数第二次分酒人数比倒数第一次人数至少多1人,假设最后一次分酒每人分到了最多的量1/2,则这次分酒人数最多不到6人
        {
            for (k=j+1; k<12; k++)//逻辑推断,倒数第三次分酒人数比倒数第二次人数至少多1人,假设最后一次分酒每人分到了最多的量1/2,倒数第二次分酒每人分到了最多的量1/3,则这次分酒人数最多不到12人
            {
                for (l=k+1; l<21; l++)//根据题意,初始分酒人数最多不到21人
                {
                    if (1/i+1/j+1/k+1/l==1)//判断船长喝的酒够不够一瓶
                    {
                        printf("%g,%g,%g,%g,%g\n",l,k,j,i,m);//按照样例输出
                    }
                }
            }
        }
    }
    return 0;//返回0
}

然而奇迹出现了,我的输出答案竟然是:
18,9,3,2,0
20,5,4,2,0
12,6,4,2,0
缺少一种,我几经周折查阅资料,一个个猜想都被我推翻了,一直找不到合适的解释,为什么却少了“15,10,3,2,0”这一种结果,理论上讲这一种结果和“18,9,3,2,0”“12,6,4,2,0”相似,为何只有这个无法输出?一直想不通。
接着朋友去网上找有关的代码,结果又出现奇迹了,他找到了一段和我的代码酷似的,如下:

#include<stdio.h>
int main()
{
    float a,b,c,d,e=0;
    for(a=0;a<=20;a++)
    {
        for(b=0;b<a;b++)
        {
            for(c=0;c<b;c++)
            {
                for(d=0;d<c;d++)
                {
                    if((1/a+1/b+1/c+1/d)==1)
                        printf("%g,%g,%g,%g,%g\n",a,b,c,d,e);
                }
            }
        }
    }
    return 0;
}

结果竟然是正确的四种结果……这究竟是怎么回事?到现在我依然没有搞明白,一种由内而外的焦虑,我不淡定了!
第一种可以理解为利用数学办法避免使用浮点型数据,第二种是使用了浮点型,结果错误,第三种也是使用了浮点型,结果却正确,更让人无奈的是第二第三种的解题思想大体相同。我排除了无限小数存在的误差导致这种情况出现的可能,但是依然无法找到真正的问题症结……希望先暂时记住这一个谜团,在以后的学习进步中可以再发现问题所在。

全部评论

相关推荐

我见java多妩媚:大外包
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务