水手分椰子问题

题目描述:

n个水手来到一个岛上,采了一堆椰子后,因为疲劳都睡着了。一段时间后,第一个水手醒来,悄悄地将椰子等分成n份,多出一个椰子,便给了旁边的猴子,然后自己藏起一份,再将剩下的椰子重新合在一起,继续睡觉。不久,第二名水手醒来,同样将椰子了等分成n份,恰好也多出一个,也给了猴子。然而自己也藏起一份,再将剩下的椰子重新合在一起。以后每个水手都如此分了一次并都藏起一份,也恰好都把多出的一个给了猴子。第二天,n个水手醒来,发现椰子少了许多,心照不喧,便把剩下的椰子分成n份,恰好又多出一个,给了猴子。请问水手最初最少摘了多少个椰子?

输入:

多组测试数据,每组输入1个整数n1 < n <= 9)

输出:

对于每组测试数据输出一行,值为最初摘的椰子数

数据样例:

5

样例输出:

15621

提示:多种可能性的情况下只求最小值

题目解析:

N个人分一堆椰子,每一个人单独分成N份并去掉一个,最后全部的人在一起将椰子分成N份并去掉一个。

分析:将椰子每次分N份并去掉一个,一共要进行这样的操作共N+1次(全部的人一起分也算是一次)

根据题目含义,我们假设y表示每一次每一个人分成的N份中的一份;

则存在一下关系:

 这个人自己拿走一份,则一共留下N-1份,另这一次,这个人分的其中一份为y,那么就还剩下N-1份;在这N-1份之中,将继续进行分配所以可以得到以下的式子:

n-1*yi=n*yi-1+1         ( *k)

(注:yi)和yi-1)分别表示第i次和第i-1次醒来的那个水手进行分配后的一份。)

这个时候,将注意力放在提示上面:多种可能性的情况下只求最小值

什么时候我们能求得最小值呢?

如果是一个单调的函数,那么将一个增函数的自变量在定义域区间增大时,那么这个函数也在增大。

换句话说,我们只需要在这个增函数增长到第一次符合我们条件的时候,我们取得那个数便是我们需要得最小值。

那么我们就需要将(*k)进行相应的变换,让它符合我们“取得一个增函数”的想法。

对问题进行思考,我们能知道,如果我们知道了自己一共有多少个,那么经过一个f运算之后,能求得一个相对小的数,使之满足最后一次分配,仍然能分成N份还能多出一个,但是如果这样考虑,我们假设自己所知道的椰子总数是我们的自变量,那么它是逐渐减小的,而且没有办法赋予一个准确的初始值(如果有的话,你为什么还要写这一串代码呢?),所以我们假设,我们知道最后一次分出的个数(事实上,在(*k)那里,我已经那样操作了),那么这样的话,我们就把这个问题做了一次倒置,即我们已经知道了最后一次的椰子个数,我们所要做的唯一一件事情就是把所有人的椰子凑起来,看看最后能不能出现一个相对合理的数(相对合理,即每一次分配,大家都能得到整数个椰子,你也不想分到半个别人已经吃过的椰子吧?)。

这样以后我们能知道,我们的椰子数量将从1开始累加,知道最后(也就是我们用于计算的第一次)分配的椰子数,然后逐层返回,当我们返回了N+1次,并且每一次分配都相对合理的时候,我们即能得到返回了N+1次后,也就是没有分配时候的椰子的总数。

所以真正要解决的就是如何从一个很小的数做到逐层返回。

我们将(*k)进行变化,能得到它每一次上升的关系:

[yi-1*n-1+1]/n=yi   *L

即通过yi-1)我们可以得到它上一次分配时的一份yi

经过一番分析之后,相信你对自己要做,有了一个明确的概念:
1:输入一个n值,表示有多少人参与到了这一次的分配

2:通过(*L)式子实现逐层返回,如果返回了N+1次,并且都成功的话,bingo,你成功了

3:如果每一次返回的途中,有一次不成功的话,那么就让最后一次y加上1,再继续实验

#include<stdio.h>
int main()
{
	double hand(int n);
	int n;
	while(scanf("%d",&n)!=EOF){
		printf("%.0f\n",hand(n));
	}
	return 0;
}
double hand(int n)
{
	double k,y;
	double ans;
	int i=1;
	k=1.0;
	y=k;
	while(i<=n){
		i++;
		y=((n-1)*y-1)/n;
		if(y!=(int)y){
			k++;
			y=k;
			i=1;
		}
	}
	ans=n*k+1;
	return ans;
}

最后第N+1次返回单独列出的原因是:最后得总是要加上自己手上那一份!

当然你也可以返回N+1次后,再加上自己那一份:都是可以的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值