请你编程95002讲评
#include <stdio.h>
int main(void)
{
int m=1,n,i=0;
do{
m=7*++i+1;
for(n=1;(m-=n)!=0&&m%7==0;n++)
m-=m/7;
}
while(m);
printf("date %d,number %d\n",n,7*i+1);
return 0;
}
程序中m表示共发奖牌总数,n表示运动会开了多少天。do…while循环不断修改m的值,而内层for循环则对固定的m模拟发奖牌的过程。整个程序简洁明快,稍嫌不足的是它仅给出了m=36、n=6这一组解。
另一种思路是先固定运动会的天数n,然后寻求满足题意的m。辽宁一位未署名读者编出了下面的Basic程序:
DIM a(30)
FOR n = 1 TO 30
m = 0
FOR i = n TO 1 STEP -1
IF m MOD 6 <> 0 THEN EXIT FOR
a(i) = i + m / 6
m = m + a(i)
NEXT
IF i = 0 THEN PRINT "m="; m, "n="; n
NEXT
END
程序中合理地假定运动会不超过30天,并取n从1~30进行循环,内层FOR循环则完成自第N天开始的逆推。设第i天发奖牌A(i)枚,按题意有A(N)=N,A(N-1)=N-1+A(N)/6,A(N-2)=N-2+(A(N)+A(N-1)/6,……故A(i)(I>1)应是6的倍数,程序中用m MOD 6 <> 0进行判断,而M=M+A(i)则完成奖牌数的累计。
这个程序完全正确,它给出了本题的两组答案。程序中数组A舍己为人嫌多余,也许作者考虑使用数组程序可读性更好些。如果不用数组,可简单地去掉其定义和A(i)=I+M/6一句,并将m=m+A(i)改为M=M+I+M/6。
有几位读者一般性地思考了“运动会奖牌数”这个题目,发现除数I(如题中的“7”)、运动会天数N、奖牌总数M存在以下关系:
N=I-1
M=(I-1)2
当然,这个关系没有包括N=1、M=1这个特例。广州的陆文杰还编出了能验证这一关系的Basic程序。河北的风舟朋友用C语言实现了一个相当通用的函数:
void DaysAndMedals(int divs)
{
int n, m,i;
for(n=1;n<30;n++)
{
m=0;
for(i=n;i>=1;i--)
{
if(m%(divs-1)) break;
m+=i+m/(divs-1);
}
if(!i) printf("m=%d,n=%d",m,n);
}
}
于是函数调用DaysAndMedals(7)就求出了本题的答案。对不同的除数I,用DaysAndMedals(I)就可以求出相应的m和n。应该说这样的设计已相当完美了。
讲评到这里,第二期的“请你编程”就告一段落了,10枚奖牌也已各有其主,他们是:
湖北 吴云洋 辽宁 未署名
浙江 吴鹏东 南京 李 烁
湖南 将春红 湖北 江 龙
重庆 百晓明 大连 高可攀
山东 勒志刚 浙江 黄越夏