请你编程95002讲评 山东 勒志刚 浙江 黄越夏 1995-04-28 很显然原题中有两个变数M、N,对应地就有两种思路,一种思路就是先固定奖牌总数M,看是否存在自然数N满足题目要求。由于题中涉及(m-1)的1/7,可知m为7的倍数+1,即m=7i+1。湖北吴云洋同学依此设计了如下的C程序: #include 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枚奖牌也已各有其主,他们是: 湖北 吴云洋 辽宁 未署名 浙江 吴鹏东 南京 李 烁 湖南 将春红 湖北 江 龙 重庆 百晓明 大连 高可攀 山东 勒志刚 浙江 黄越夏