水手分椰子

5个水手分椰子

问题描述

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

递推设计

设置 y y y 数组, 第 i i i 个水手藏椰子数为 y ( i ) ( i = 1 , 2 , . . . , 5 ) y(i) (i = 1,2 ,..., 5) y(i)(i=1,2,...,5) ,第二天5个水手醒来后各分得椰子为 y ( 6 ) y(6) y(6) 个, 依照题意, 设椰子总数为 x x x ,则 x = 5 y ( 1 ) + 1 x = 5 y(1) + 1 x=5y(1)+1
相邻两人所藏椰子数 y ( i ) y(i) y(i) y ( i + 1 ) y(i+1) y(i+1) 之间的关系为
4 y ( i ) = 5 y ( i + 1 ) + 1 y ( i + 1 ) = ( 4 y ( i ) − 1 ) / 5 4y(i) = 5y(i+1) +1 \\ y(i+1) = (4y(i)-1)/5 4y(i)=5y(i+1)+1y(i+1)=(4y(i)1)/5

边界条件: y ( i ) 均 为 整 数 y(i) 均为整数 y(i)

程序源代码
#include<stdio.h>
#include<math.h>
int main(){
	
	int i;
	double k,x,y[7];
	i = 1;
	k = 1.0;
	y[1] = k;
	while(i <= 5){
		i++;
		y[i] = (4*y[i-1]-1)/5;
		if(y[i] != floor(y[i])){
			k = k + 1.0;
			y[1] = k;
			i = 1;
		}
	}
	x = 5*y[1] + 1;
	printf("5个水手分椰子,原有椰子至少有:%.0f个\n",x);
	return 0;
} 
算法改进

前面使用从前往后递推,从大推小,次数较多。从后往前推,从小推大,可以精简递推的次数。
递推式:
y ( i ) = ( 5 y ( i + 1 ) + 1 ) / 4 y(i) = (5y(i+1)+1)/4 y(i)=(5y(i+1)+1)/4

k取值的改进:为了确保从后往前推出的数是一个整数,初始值应该为 3,每次 k=k+4 来保证所推出的数都是整数

改进后程序源代码
#include<stdio.h>
#include<math.h>

int main(){
	int i;
	double k,x,y[7];
	i = 6;
	k = 3.0;
	y[6] = k;
	while(i > 1){
		i--;
		y[i] = (y[i+1]*5 + 1) / 4;
		if(y[i] != floor(y[i])){
			k = k + 4.0;
			y[6] = k;
			i = 6;	
		}
	}
	x = 5*y[1] + 1;
	printf("原有椰子数至少为:%0.0f\n",x);
	return 0;
}

n个水手分椰子

问题描述

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

递推

递推关系式:
y ( i ) = ( n y ( i + 1 ) + m ) / ( n − 1 ) y(i) = (n y(i+1)+m)/(n-1) y(i)=(ny(i+1)+m)/(n1)

k值取值:初始值为 k = n − m − 1 k=n-m-1 k=nm1 , 每次 k = k + n − 1 k = k+n-1 k=k+n1 递增

程序源代码
#include<stdio.h>
#include<math.h>
int main(){
	
	int i,m,n;
	double k,x,y[10];
	
	printf("请输入人数 n:");
	scanf("%d",&n);
	printf("请输入每次剩下的椰子数 m:");
	scanf("%d",&m);
	
	i = n + 1;
	k = n - m - 1;
	y[n+1] = k;
	while(i > 1){
		i--;
		y[i] = (y[i+1]*n + m)/(n-1);
		if(y[i] != floor(y[i])){
			k = k + n - 1;
			y[n+1] = k;
			i = n + 1;
		}
	}
	x = n*y[1] + m;
	printf("原有椰子至少为:%.0f\n",x);
	for(i=1;i<=n;i++){
		printf("第 %d 个水手面临的椰子:%0.0f = %d * %0.0f + %d",i,n*y[i]+m,n,y[i],m);
		printf("\t藏 %.0f\n",y[i]);
	}
	
	printf("最后一起分时的椰子数:");
	printf("%0.0f = %d * %0.0f + %d \n",n*y[n+1]+m,n,y[n+1],m);
	printf("每人分 %0.0f 个\n",y[n+1]);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值