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)/(n−1)
k值取值:初始值为 k = n − m − 1 k=n-m-1 k=n−m−1 , 每次 k = k + n − 1 k = k+n-1 k=k+n−1 递增
程序源代码
#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;
}