您的位置:首页 > 其它

猴子分桃问题

2017-12-17 19:14 281 查看

描述

有一堆桃子和甲、乙两组猴子,甲组有 3 只猴子,乙组有 5 只猴子。甲组的猴子先看到 这堆桃子。第一只猴子把桃分成了相等的 3 堆,多出 2 个。于是,它吃掉了 2 个,又拿走了 1 堆;第二只猴子把 2 堆桃子合在一起,又分成相等的 3 堆,又多出 2 个。于是,它也吃掉 了 2 个,拿走了 1 堆;第三只猴子也照样办理。甲组猴子走后,乙组猴子也看到剩下的 2 堆 桃子,第一只猴子把桃分成了相等的 5 堆,多出 1 个。于是,它吃掉了 1 个,又拿走了 1 堆; 第二只猴子把 4 堆桃子合在一起,又分成相等的 5 堆,又多出 1 个。于是,它也吃掉了 1 个,拿走了 1 堆;第三、四、五只猴子也照样办理。请设计算法,求:8 只猴子走后至少还 剩下多少个桃子?原来这堆桃至少有多少个?

我的想法

这道题是课上数据结构的一道题,经度娘搜索后找到了解法然而是用pascal语言写的(http://www.doc88.com/p-6502904388261.html),也就没有细看直接上手了。

不同于一般的倒推法,这里甲组和乙组分别代表两个循环,所以我们需要特别注意如何处理这两个循环的关系。

如果我们将桃子的数量用数组a[9]存放,a[0]表示8只猴子分完后剩下的桃子数量,a[8]表示未分桃子时的桃子总数。

可以发现乙组猴子每分一次桃子执行的操作是a[i−1]=(a[i]−1)/5∗4倒推表示即为a[i]=a[i−1]/4∗5+1在循环中实现时判断条件是a[i]%4==0,这一点可以从a[i-1]=(a[i]-1)/5*4中看出,其现实含义是每只乙组猴子所面对的桃子数量都是由前一只猴子分剩下的四堆桃子拼成的。

然而唯一的例外是乙组的第一只猴子,他所面对的桃子数量应该符合甲组分桃的规则即a[5]%2==0,是由甲组最后一只猴子分剩下的两堆拼成的。

同理甲组猴子分桃操作满足规则a[i]=a[i−1]/2∗3+2与乙组相同,甲组第一只猴子所面对的桃子数量(即桃子总数)不需要满足甲组规则,由于在他之前没有任何分桃操作也就无需满足所谓的分桃规则,直接得出答案。

在处理完循环内的数量关系后,我们来斟酌一下两个循环的关系。显而易见,寻找答案时循环绝不只执行一次,我们需要添加一些标识符来选择循环和循环开始的位置,具体见注释。

代码

#include<iostream>
using namespace std;
int panduan1(long &a)//乙组判断
{
if(a%4==0)
return 1;
else
return 0;
}
int panduan2(long &a)//甲组判断
{
if(a%2==0)
return 1;
else
return 0;
}
int main()
{
long a[9];
int i=1,flag1=0,flag2=0,flag3=0;//循环控制标识符
a[0]=4;
while(flag3==0)//大循环
{
while(flag1==0)//倒推法,乙组循环
{
a[i]=a[i-1]*5/4+1;
if(panduan1(a[i])==0)//不符合规则,重新开始
{
a[0]=a[0]+4;
i=0;
}
i++;
if(i==6)//对乙组猴子开始分桃的情况做判断
{
if(a[5]%2==0)//可以与甲组循环衔接
{
flag1=1;//跳出乙组循环
flag2=0;//进入甲组循环
}
else//不符合甲组分桃规则,重新开始
{
a[0]=a[0]+4;
i=1;
}
}
}
while(flag2==0)//倒推法,甲组循环
{
a[i]=a[i-1]*3/2+2;
if(panduan2(a[i])==0)//不符合规则,需要再次进入上一循环
{
flag2=1;//跳出甲组循环
flag1=0;//进入乙组循环
i=0;
a[0]=a[0]+4;
}
i++;
if(i==8)//桃子总数不需要满足规则,直接计算
{
a[i]=a[i-1]*3/2+2;
flag2=flag3=1;//跳出本循环和大循环
}
}
}
cout<<a[8]<<endl;//输出结果
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  倒推法