从_经典算法问题_猴子分桃问题_分析递归问题的解题思路_随笔

从_经典算法问题_猴子分桃问题_分析递归问题的解题思路

猴子分桃问题

海滩上有一堆桃子,m只猴子来分。第一只猴子把这堆桃平均分为m份,多了一个,把多的一个扔到海里,拿走了一份。第二只猴子又把剩下的桃子平均分为m份,多了一个,丢入海里,拿走一份。同理,第三,第四…第m只猴子也像前两只猴子那样操作。请问海滩上原来最少有多少个桃子?

问题分析

这是一个典型的递归问题。就像我们高中课堂上学的数列那样,一些问题存在着递推公式。基于思考习惯的延续,面对这种问题,我们第一步也是应该找出它的递推公式。当然,递推可以正着推,也可以反着推。但是生活中的不少问题都存在着有界性,比如人们的身高通常为正数,考试分数也是正数那样。也许我们可以找一个极大数来反着推(某些情况这的确符合我们的思维模式),但是这存在一个避不开的问题:究竟一个数多大才是极大呢?所以,笔者更希望从有界的起点,较小数开始推理。
同样,生活中的问题也常常存在着离散性。就像买手机最少是一台一台的买,而不是说买半台。同样到微观领域,即便是能量也是一份一份的量子态。这里的递推问题也常常呈现出这种离散状态,猴子一只只,桃子一个个,不可再分。
考虑桃子的量最少时是最后一只猴子(第m只)做完操作后。那么基于不可再分的离散性条件,不妨设它将得到的桃子分为了m份多一个,且这里的每份是1个桃子。
因为最后的猴子要取走一份桃子(也就是一个),最终剩余(m-1)个桃子,而第m个猴子得到的桃子(也就是第m-1只猴子操作后剩余的桃子) 为
m*(m-1)/(m-1)+1
显然,基于我们刚说的离散原则,这里上式的第一项必然为整数,第二项为它丢掉的那个桃子。为便于记录,为我将(m-1)替换为sum。故而可以得出递推公式为:
sum=m*sum/(m-1)+1
这个递推公式对m只猴子的操作都是适用的,所以我们可以不断尝试sum,使得所有的猴子都满足递推公式。

参考代码(c++版)

#include <iostream>

using namespace std;


/*
函数名:getSum
函数功能:返回m个猴子都进行自己的分配时所需要的最小桃子个数(既然是试错大概率出现极大数满足试错条件)
返回值:int
参数:int m
*/
int getSum(int m);


int main(void)
{
	cout << "请输入猴子个数";
	int m;
	cin >> m;
	cout << getSum(m);
	return 0;
}


/*
函数名:getSum
函数功能:返回m个猴子都进行自己的分配时所需要的最小桃子个数(既然是试错大概率出现极大数满足试错条件)
返回值:int
参数:int m
*/
int getSum(int m)
{
	int sum = 0;//保存递归需要求的结果
	int n = 1;//用来记录试的记录
	int i = 0;
	while (1)//不知道什么时候试错成功,死循环试错
	{
		sum = (m - 1) * n;//n放到合适的表达式里面来试错,同时确定递推的首项,因为最后一次一份为一个桃子未必能满足所有递推条件,故而试错。但基于此,他必然是m-1的整数倍。
		for (i = 0; i < m; i++)//试错需要试的一连串内容满足离散性条件
		{
			if (m * sum % (m - 1) != 0)//不满足离散性条件,进行下次试错
			{
				break;
			}
			sum = m * sum / (m - 1) + 1;//简单的逻辑,既然满足离散性条件,等号右边第一项必然为整数,只需加上余数即可
		}
		n++;//下次试错
		if (i >= m)//应该试错的内容完结,退出循环
		{
			break;
		}
	}
	return sum;
}
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值