人和猴子分配椰子问题

版权声明:可以转载,但请先关注我公众号——光宇广贞 https://blog.csdn.net/hikaliv/article/details/4225660

      五男一猴子在一个岛屿上。他们度过了第一晚采收椰子。在夜间,一名男子醒来,并决定拿走他那一份椰子。他分为五个份。椰子剩下来一个,他把它给猴子,然后藏起他的份额,回去睡觉。
      不久另一名男子醒来后,也做了同样的事情。经过划分为5份椰子,剩余一个给猴子,拿走自己的,又回到床上。第三,第四和第五名男子一样。第二天早上,他们都醒了,他们剩下的椰子分成五个平摊。这一次没有椰子被遗留下来的。
      问题要输入一个N,表示椰子个数,让求P,最大的人数能满足这个条件,分P次,每次正好剩一个给猴子,最后一次省的个数正好是人数的倍数


f(n <0>) = n;
f(n <i+1>,p) = (f(n <i>)-1) * (p-1) / p; 0 <= i < p;
f(n <p>,p) = pm,m 为整数。

消去f(n <p>,p)有
pm = n * ((p-1)/p)^p - Sum( ((p-1)/p)^i, i=1:p)
pm = n * ((p-1)/p)^p + (p - 1)( ((p-1)/p)^p - 1 )

考察 ((p-1)/p)^p 的函数图像可知: 1、p < 5 时导数值很大,增长最快。
2、p >= 4 时,值过 0.3
3、p = 24 时,值过  0.36
4、p 直到百万,值仍不过 0.3679

因此可认为  ((p-1)/p)^p < 0.37,则
pm < 0.37n - 0.63(p-1)

当 m = 1 时,p 最大,有
1.63p < 0.37n + 0.63,忽略常数项
可得 p < 0.227n
所以 p 的取值范围是很小的。事实上,m 可能要比 1 大得多

那我们来看看,当 m = 1 的时候,p 与 n 的关系,这里面 p 与 n 都应是整数
p = 1 : 1 : 3*1e7
则当 p = 2 的时候 n = 11 为整数。也就是说,测试三千万个p,当 m = 1 时,只有 p = 2 n = 11 满足条件
也即 m = 1 只有一个特例成立。

更一般的情况 m > 1,比如说 m = 2 时呢?
可得 p < 0.14n,更小了。
当 m = 2 时,p 与 n 的关系:
p = 1 : 1 : 3*1e7
则当 p = 2, 3, 24283182 时,n = 19, 25, 173742417 为整数。
m = 3 呢?
可得 p < 0.102n,更小。
当 p = 2, 18138042 时,n = 27, 179079202 为整数。
m = 4 呢?
可得 p < 0.0799n,小吧。
当 p = 2, 14384493, 17952777 时,n = 35, 181121042, 226050766 为整数
m = 5 呢?
可得 p < 0.066n
当 p = 2 时,n = 43 为整数
m = 6 呢?
可得 p < 0.056n
当 p = 2、17275954、29680590 时,n = 51、311450436、535080878
m = 7
p < 0.0485n
p = 2、14333173、17300311、26742099 时,n = 59、297359666、358916666、554798405


不测了,测试中大数多情况 p 为 2 人的居多,或者,岛上有上千万的人分数百亿的椰子……那些椰子放哪儿都是个问题。

 

最后测一个 m = 100

p < 0.0037n,这也太小了吧,千分之三了。

p = 2 4588077 5872121 7366469 9074646 11807665 15939607 18255034 20749254 22115823 22955497 23585595 26559095 27414265 27642455 27929303 29690190

n = 803 1255052379 1606298075 2015071687 2482337469 3229945155 4360223282 4993600150 5675885221 6049705324  6279395176

 

还是有 2 个人的情况。

 

结论:让 p 取到三千万人之内来测满足p与n同为整数的情况。m为最后一次每人分得的椰子数,须为整值。p 为 2 时多。测试给出了几种可能性。由公式可得,p 的遍历范围可以相比n来说很小。有的人从 n - 2 开始遍历,其实,从结果可以看出,几乎99%的情况是在做无用功。


这是一道ACM题,原贴见

http://topic.csdn.net/u/20090530/10/dc60c446-c153-42e7-a39d-597d1f307773.html

我在原贴的回复中说错了,在此文中更正。

 

测试代码:

阅读更多
换一批

█▉人和猴子分配椰子问题

05-30

[size=24px]大[color=#000080]侠们帮忙看看,程序没错,不错超时,小弟菜鸟一个,不晓得怎样改进下才不超时?rn题目大意: 故事讲述了五男一 猴子在一个岛屿上。他们度过了第一晚采收椰子。在夜间,一名男子醒来,并决定拿走他那一份椰子。他分为五个份。椰子剩下来一个,他把它给猴子,然后藏起他的份额,回去睡觉。 rnrn不久另一名男子醒来后,也做了同样的事情。经过划分为5份椰子,剩余一个给猴子,拿走自己的,又回到床上。第三,第四和第五名男子一样。第二天早上,他们都醒了,他们剩下的椰子分成五个平摊。这一次没有椰子被遗留下来的。 rnrn问题要输入一个N,表示椰子个数,让求P,最大的人数能满足这个条件,分P此,每次正好剩一个给猴子,最后一次省的个数正好是人数的倍数[/color];[/size]rnrn代码:rn超时了~~rn//完成时间:2009年5月29日22:36:39,ps,本程序可以改进,主要是p,不用搞到N+1,不过该是几我也不知道rn#includernusing namespace std;rnrnint Fenpei(int N)rnrn int p;rn int yes;//记录当前椰子个数是否符合标准rn int i;rn int max=1;rn for(p=N-2;p>1;p--)//p不应该是N-1以上的rn rn int *n=new int [p+1];//第0个存放初值rn int *s=new int [p+1];//n,s分别表示第k次拿走的 椰子数,拿走后剩余数rn n[0]=0;rn s[0]=N;rn yes=1; //复位rn i=1; //复位rn while(i<=p)//有p个人,就拿走p次rn rn if((s[i-1]-1)%p != 0)//上次剩余个数无法表示成5K+1的形式,无法分配rn rn yes=0;rn break;rn rn elsern rn n[i]=(s[i-1]-1)/p;rn s[i]=s[i-1]-n[i]-1;//------------注意,每次拿走还给了猴子一个rn rn i++;rn rn if(yes==1 && s[p]%p ==0)//每次都能 正确拿走,最后剩下s【p】还能平均p等分rn rn cout<>num && num!= -1)rn rn Fenpei(num);rn rn return 0;rn

没有更多推荐了,返回首页