请你编程95002讲评

Author: 山东 勒志刚 浙江 黄越夏 Date: 1995-04-28

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