猴子分桃问题的解决方法

猴子分桃问题的解决方法

1 问题

1979年,李政道博士给中国科技大学少年班出过一道智趣题:5只猴子分一堆桃子,怎么也分不成5等分,只好先去睡觉,准备第二天分。夜里1只猴子偷偷爬起来,先吃掉一个桃子,然后将其分为5等份,藏起自己的一份就去睡觉了;第二只猴子又爬起来,吃掉一个桃子后,也将桃子分成5等份,藏起自己的一份睡觉去了;以后的3只猴子都先后照此办理。问最初至少有多少个桃子?

现在考虑更加的一般性,说是m只猴子,问最初最少有多少个桃子?

 

2 解答:

2.1 递推解法

设最初有x个桃子,猴子的个数是定值m,用Tk表示第k的猴子占有的桃子总数,那么容易知道:


从上面的公式可以看出 必须是 的整数倍,所以可以推出:


2.2 整体思考法

这个算法算是吊炸天的,它也是最直接的,其实它也是在上面的推导过程中提炼出来的。

m只猴子,x个桃子,再借给猴子们(m-1)只桃子,这个时候第一只猴子得到的桃子是(x + m-1)的 1/m ,需要注意的是第一只猴子得到的桃子中并不包含借的桃子数目,也就是说借的(m-1)只桃子一个都没有给第一只猴子。然后第二只猴子分桃的时候,我们再把这没用上的(m-1)个桃子给补上,此时第二只猴子得到的桃子数目是第一次分完后剩下的 。也就是说第二只猴子分得: ,其中 是第一只猴子拿走桃子后再加上m-1个桃子的数目。以此类推,下一个猴子的拿的桃子数目都是前一个猴子拿的桃子数目的 ,这样就很容易得出:

 

2.3 编程递归解决

如要递归只需要知道前后两次剩余桃子之间递推关系就可以了,这里很容易知道前后的关系是:  

然后从x=1,开始遍历,直到x能满足每次都可以平均分配为止。代码如下所示:

#include <iostream>
using namespace std;
bool left(int x,int ntimes,int nMonkeys);

void main()
{
	cout<<"Please input the monkeys"<<endl;
	int nMonkeys;
	cin>>nMonkeys;
	
	int x = 2;
	while( !left(x,nMonkeys,nMonkeys))
		x++;
	cout<<"The number of peach is :"<<x<<endl;
}

bool left(int x,int ntimes,int nMonkeys)
{
	if (ntimes ==0)
		return true;
	else
	{
		if( (x-1)%nMonkeys !=0 )
			return false;
		else
			return left( (x-1)*(nMonkeys-1)/nMonkeys,ntimes-1,nMonkeys);
	}
		
}


  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
猴子分桃问题描述如下:五只猴子在海边捡到了一堆桃子,它们决定分掉这堆桃子,但是它们发现它们太累了,于是决定先休息一会儿,等到第二天再分。于是这五只猴子开始分,第一只猴子把桃子分成了五堆,每堆多一个;第二只猴子把剩下的桃子分成了五堆,每堆多一个;然后第三只、第四只、第五只猴子都按照同样的方法分桃。最后发现桃子刚好分完,问这堆桃子最少有多少个? 我们可以利用单循环链表来解决这个问题。具体思路如下: 1. 最后一个猴子分完桃子后,剩下的桃子数量为 1。 2. 第五只猴子得到的桃子数量为 `(4 * 上一只猴子得到的桃子数量 + 1)`,即 `4x + 1`。 3. 根据上面的公式,倒推出第四只猴子得到的桃子数量,为 `(5x + 1) / 4`。 4. 继续倒推,可以得到第三只猴子得到的桃子数量为 `(25x + 6) / 20`,第二只猴子得到的桃子数量为 `(125x + 31) / 100`,第一只猴子得到的桃子数量为 `(625x + 156) / 500`。 5. 然后我们可以通过一个 while 循环,不断地将剩下的桃子数量分成五份,每份多一个,直到最后剩下的桃子数量为 1,这样就可以求出这堆桃子最少有多少个。 下面是利用单循环链表结构实现的 Python 代码: ```python class Node: def __init__(self, data): self.data = data self.next = None def monkey_divide_peach(): last_node = Node(1) for i in range(4): current_node = Node((last_node.data * 5 + 1) // 4) current_node.next = last_node last_node = current_node peach_num = last_node.data current_node = last_node while current_node.next: peach_num = peach_num * 5 + 1 current_node = current_node.next while peach_num % 4 != 0: peach_num += 5 ** 5 return peach_num print(monkey_divide_peach()) # 输出:3121 ``` 在上面的代码中,我们首先根据猴子分桃的规律,用单向链表倒推出最后一只猴子得到的桃子数量,然后通过一个 while 循环,不断地将剩下的桃子数量分成五份,每份多一个,直到最后剩下的桃子数量为 1,这样就可以求出这堆桃子最少有多少个。最后输出结果为 3121。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值