浅显易懂、简单粗暴得处理猴子分桃问题

作者 : 开心源码 本文共4589个字,预计阅读时间需要12分钟 发布时间: 2022-05-14 共152人阅读

原因

海滩上有一堆桃子,五只猴子来分。第一只猴子把这堆桃子分为五份,多了一个,这只猴子把多的一个仍入海中,拿走了一份。第二只猴子把剩下的桃子平均分成五份,又多了一个,它同样把多的一个扔入海中,拿走了一份,第三、四、五只猴子都是这样做的,问海滩上原来最少有多少个桃子?

起初我看到这道题是崩溃的,咋又碰到数学题啦!我数学向来差的一批,所以这道题我是真真的没想出啥处理的方法,于是乎我便到网上查找解题方案,好家伙,不查不要紧,一查我更崩溃了,由于我发现那些解释我一个都没懂!虽然N多个人从N多个方向提出理解题思路,但我是真弄没弄清楚他们列出来的数学公式。连解题思路我都没懂,就更别谈网上的代码了,代码复制下来是能跑出正确结果,但是从开头的数值初始化,到最后的打印语句,我没有一行能了解的o(╥﹏╥)o

就在我万念俱灰、瞎搞乱搞之际,忽然一条思路在我脑袋里冒出,顺着这条思路我瞬间理清理解决方法,并相当轻松的完成了代码!!(不要问我思路咋忽然就理清了,我也母鸡啊╮(╯▽╰)╭)这个思路不需要你有啥数学知识,也不用列什么数学公式,只有非常简单的一点逻辑分析,我相信在这个思路下,大家就算数学糊烂到爆,也能了解这道题,毕竟数学再烂能有我烂!?

问题分析

分析这个猴子偷桃的问题之前,可以参考一下我之前写的这篇,暴力解三元一次方程的思路:用for循环解三元一次方程的思路。

拥有好的数学功底,诚然能更好的写出程序,但是程序不仅仅只有数学,还有逻辑分析。数学解不出来,我就用程序暴力处理呗,程序不就是代替我们人类做起来重复又繁琐的事嘛。回到猴子分桃的问题上来, 目前咱们从题目中得到的信息说多不多,说少不少,咱们一步一步得来提取:

首先,有一个固定的数值是显然易见的,那么就是猴子有5只,他们一共分了5次桃。那咱们就将猴子的变量先提取出来,monkey = 5呗。

而后,每次分桃时候的桃子数量有5份+1,至于每份是多少,不知道。最难的地方就在这,每份的桃子数不光不确定,而且每次分完桃子后,桃子的数量还会变化!!不过别急着用数学的公式来处理他,这里尽管是最难搞定的,但也是突破口。

咱继续进一步思考,猴子每次会分5份桃子+1个,而后丢掉一个,拿走一其中份,这不就代表着 将 桃子数先 – 1,而后再拿走五分之一数量的桃子,只剩下五分之四的桃子,并且下一次分桃又重复着这种操作,总共进行了5次。 (不要嫌我啰嗦反复讲这些已知的,代码马上即可以写出了)。同样的操作,进行了5次,嗯哼,大家有联想到程序里的什么吗!? 没错,这不就是循环嘛!! 一共循环了5次呗。OK,咱们现在知道要弄一个循环出来了,循环的执行代码块又是啥咧?

int i = 1;// 循环的条件变量while(i <= 5) {    //这里要做点啥咧......    i++;}

有一个数,要 – 1后 再 剩下 五分之四,并且要不断的进行五次,也就是说,咱们要求的这个数要达到这些条件才符合我们的要求。符合要求,嗯哼?大家又联想到程序里的什么吗?是滴,就是判断嘛,一个数要符合这个条件并持续五次,才算达到要求。OK,那不就代表咱们要把判断条件放到那个五次循环里进行嘛,循环执行完毕后都通过了判断,就代表找到那个数了!

咱们要最终找到的那个数是桃子,所以变量为了见名知意,就定为peach哈

int i = 1;while(i <= 5) {    // -1后才能分平均五份,不就代表着模5要等于1嘛    if (peach % 5 == 1) {        // 每次弄完后,就剩下原数量的 - 1后的五分之四了,所以每次要将这个数升级一下        // peach / 5就代体现在的每份桃子的数量        // 拿掉一份后,就是只剩下四份,所以才乘以4        // 有人问不是多了一个桃子嘛,怎样不用-1呢,由于程序/5会直接减掉余数,所以不用-1后再除。        // 假如想-1后再除以5,也是一样的,只是没必要        peach = (peach / 5) * 4;    }    i++;}

非常好,感觉有点意思了。现在下一个问题自然就摆在我们眼前,peach我该定义成啥数啊?呃…要定义啥数我也不知道,要是我知道的话那就不用求这个数了,答案不就出来了嘛。 别急,不知道啥数,咱们就找嘛,我们一个数字一个数字的去试,看看究竟哪个数符合这个条件,答案不就出来了? 一个一个数字的去试,咱们人做起来一定要疯,不过聪明的你一定想到了,用程序去做呗!注意哦,这里已经将问题的处理思路一律说出来了,就是 一个数一个数的去尝试,假如符合题意条件的就代表那个数找到了! 咱们现在要做的就是,怎么去一个数一个数的去找:

int i = 1; int peach = 1; // 要寻觅的数,咱们从最小的整数开始往下一个一个的找while(i <= 5) {    if (peach % 5 == 1) {        peach = (peach / 5) * 4;    }    i++;    peach++; // 每循环一次peach的数量就加一次,而后再进行尝试判断}

写到这里有一个程序的问题,就是循环只有五次,peach的数量只能加五次,这五次要是没符合,程序还是会结束,所以这里就要进行逻辑上的优化,以达到我能一个数一个数进行尝试的要求(这一步和题目其实没啥关系,就是程序逻辑的优化):

int i = 1; int peach = 1; // 要寻觅的数,咱们从最小的整数开始往下一个一个的找while(i <= 5) {    if (peach % 5 == 1) {        peach = (peach / 5) * 4;        i++;// 只有数值判断成功了,才会将循环条件升级    } else { // 假如数值没有判断成功,就代表数值不符合要求,就要继续找下一个数        peach++; // 每循环一次peach的数量就加一次,而后再进行尝试判断    }}

为了讲解的更清楚,这一步我没有完全优化好,就是说这块代码还是有很多问题。比方,要是一个数值只需符合 % 5 == 1了,就会进行代码块里的数值升级(peach呀,循环条件i呀都会变化掉),但是我们要求的是得连续符合5次才行,现在一次符合就将我们数值给变化了,那可不行,所以咱进行下一步优化,肯定要保证,假如不是连续符合五次的话,我的其余数值就不能变化,而后重新再来,进行下一个数值的判断

int i = 1; int peach = 1;int count = 1; // 由于每次分桃的数量会升级,所以必需额外公告一个变量来不断递增做试验while(i <= 5) {    if (peach % 5 == 1) {        peach = (peach / 5) * 4;        i++;    } else {          // 每循环一次peach的数量就加一次,而后再进行尝试判断,为了避免peach在if代码块里变化过,所以额外的一个变量来做升级        count++;        peach = count;        i = 1; // 为了避免循环条件变量i也被升级过,所以只需有一次判断不成功就重新来过,重新设为初始值    }}

至此代码就已经完全实现了,为了更加的见名知意,我们将循环条件变量i改一下名,既然是五只猴子来分,就将i改成monkey,以下是完整代码,我会将所有注释都加上,好方便了解(假如看完整代码对其中某一步不明白,就看一下之前我是怎么一步一步添加代码的):

/** *  * @function 猴子分桃 * @author RudeCrab * @date 2019年4月1日上午8:30:21 * @version 1.0.0 * @copyright RudeCrab */public class Peach {    public static void main(String[] args) {        int monkey = 1;// 要分桃(判断)的次数,就是到第几个猴子分桃了        int peach = 1;// 每次分桃(判断)的总数,用来判断能否符合条件        int count = 1;// 由于每次分桃(判断)后数量会升级,所以必需额外公告一个变量来递增做试验        // 循环进行分桃判断        while (monkey <= 5) {            // 怎么才算分桃(判断)成功呢,就是要%5后还剩一个,而后来五次            // -1后才能分平均五份,不就代表着模5要等于1嘛            if (peach % 5 == 1) {                // 每次弄完后,就剩下原数量的 - 1后的五分之四了,所以每次要将这个数升级一下                // peach / 5 就代体现在的每份桃子的数量                // 拿掉一份后,就是只剩下四份,所以才乘以4                // 有人问不是多了一个桃子嘛,怎样不用-1呢,由于程序/5会直接减掉余数,所以不用-1后再除。                // 假如想-1后再除以5,也是一样的,只是没必要                peach = (peach / 5) * 4;                // 分桃成功的话,就将循环条件变量monkey进行升级                monkey++;            } else { // 假如数值没有判断成功,就代表数值不符合要求,就要继续找下一个数                // 代表刚才那个数字不能达到五次的要求,所以重新再来                                count++; // 为了避免peach在if代码块里变化过,所以额外的一个变量来做升级                peach = count; // 而后peach重新被赋值,这样peach就算判断失败了,也不会受影响                monkey = 1; // 为了避免循环条件变量也被升级过,所以只需有一次判断不成功就重新来过,重新设为初始值            }        }        // 最后整个循环执行完毕了,就代表数值找到了,打印数值就可        // 这里为啥不打印peach呢,由于peach在代码块里每次分桃(判断)后都被升级了,所以count才是真实数值        System.out.println("桃的最小总数为:" + count);    }}

最后输出结果为3121,完美求出结果。这个解题思路说白了就是暴力求解,一个数一个数的去尝试判断,哪个数能符合题意的就代表数值找到了。 是不是用不到难以了解的数学公式就搞定了,嘿嘿。其实代码量非常少,根本没多少行,但是为了方便了解,所以我的注释尽量加的足够多,大家要是看着一堆注释要点晕,可以先将代码复制下来,而后将注释单独保存,将代码和注释对照查看一定能够更好的了解!

到这里大家以为就结束了嘛,nonono,要是这个思路只能处理这一个问题,这顶多叫这一题的特定方法,既然我说了是一种解题的思路,就代表这一种类型的问题都可以搞定,那么接下来让我们看一下另一个 猴子分桃问题。

扩展练习

有一只猴子,摘了很多桃子,他每天吃掉少量,剩下的桃子比之前的一律的一半少一个。他吃了十天才吃完,请问他一共摘了多少桃子?

看到这个问题是不是觉得不难,按照之前的方法去解就OK了咯,这和上一题不同点就只是在于数值判断的条件循环的次数。 我就不一步一步分解这一题了,直接贴上所有代码和注释,假如期间有不明白的,回到文章前面看一下思路就能搞定:

public static void showPeach2() {    int day = 1; // 天数,即循环的判断条件    int peach = 1; // 桃子数,即要求出的值    int count = 1; // 额外的变量,用来保持桃子数量的升级    while (day <= 10) { // 这里改成10次循环        if (peach % 2 == 0 && peach > 0) { // 由于0%2也会等于0,所以得加一个限定条件数量要大于0才行            peach = peach / 2 - 1; // 升级变量            day++; // 升级循环条件        } else { // 假如没有判定成功,代表重新来过            count++;            peach = count;            day = 1;        }    }    System.out.println("总桃子为:" + count);    /*输出结果为2046*/}

总结和思考

和解三元一次方程一样,数学咱不会解,就用程序来暴力解,毕竟程序可以替人类做那些重复繁琐的事嘛,这也是程序的用途所在!

假如对于这题还有地方不明白,请留言,咱们一起交流

说明
1. 本站所有资源来源于用户上传和网络,如有侵权请邮件联系站长!
2. 分享目的仅供大家学习和交流,您必须在下载后24小时内删除!
3. 不得使用于非法商业用途,不得违反国家法律。否则后果自负!
4. 本站提供的源码、模板、插件等等其他资源,都不包含技术服务请大家谅解!
5. 如有链接无法下载、失效或广告,请联系管理员处理!
6. 本站资源售价只是摆设,本站源码仅提供给会员学习使用!
7. 如遇到加密压缩包,请使用360解压,如遇到无法解压的请联系管理员
开心源码网 » 浅显易懂、简单粗暴得处理猴子分桃问题

发表回复