Bootstrap

实验8-1-8 报数(20 分)

实验8-1-8 报数(20 分)

报数游戏是这样的:有n个人围成一圈,按顺序从1到n编好号。从第一个人开始报数,报到m(<n)的人退出圈子;下一个人从1开始报数,报到m的人退出圈子。如此下去,直到留下最后一个人。

本题要求编写函数,给出每个人的退出顺序编号。

函数接口定义:

void CountOff( int n, int m, int out[] );

其中n是初始人数;m是游戏规定的退出位次(保证为小于n的正整数)。函数CountOff将每个人的退出顺序编号存在数组out[]中。因为C语言数组下标是从0开始的,所以第i个位置上的人是第out[i-1]个退出的。

裁判测试程序样例:

#include <stdio.h>
#define MAXN 20

void CountOff( int n, int m, int out[] );

int main()
{
    int out[MAXN], n, m;
    int i;

    scanf("%d %d", &n, &m);
    CountOff( n, m, out );   
    for ( i = 0; i < n; i++ )
        printf("%d ", out[i]);
    printf("\n");

    return 0;
}

/* 你的代码将被嵌在这里 */

输入样例:

11 3

输出样例:

4 10 1 7 5 2 11 9 3 6 8

代码:

void CountOff( int n, int m, int out[] )
{
    int i=0,z=0,h,a[MAXN];//定义出了i(总计数器),z(报数计数器),h(顺序计数器),a(数组)
    while(i<n)
    {
        a[i]=i+1;
        i++;
    }
    i=0;//先把数组充满数
    for(h=0;h<n;)
    {
        if(a[i]!=0)
            z++;//模拟报数过程,z要从0记起,这样才能报三次,Z为3,准确计数
        if(z==m)//当计数器满m时,就是该移出这个人了,进行移出操作
        {
            h++;
            out[i]=h;
            z=0;//计数器清零
            a[i]=0;//因为从1记起,数组中无0,所以移出的记为0,代替删除操作
        }
        i++;//判断完了一个数,下移
        if(i==n)//防止i溢出
            i=0;
    }
}

        这个题目对于我刚学的时候来讲就是难题,暑假又做了一遍,感觉仍有些不明朗之处,来分析一波。

        这个题我是用的模拟过程的方法,即把报数过程用循环模拟出来,对每个数进行条件分析,简单来说,就是每次循环就是在报数,当符合出去的条件,就对其进行模拟操作,但是模拟的过程中我遇到一些麻烦。我遇到的麻烦就是顺序和逻辑出了问题,我先是把z记为了1,这是最大的问题,在多次循环中z会引起越来越大的错位,从而让程序非正常运行。

        其次是计数器自增的逻辑顺序问题。应该保证每一次循环都是对一个数据进行的完整的分析,只有分析完全后,才能进行i的自增。

        大体思路:模拟进行报数操作,利用循环来实现,每循环一次相当于一个人报数一次,但每次循环又有更大的含义,不能止步于报数一次,它仅是包含报数的功能,同时还应该包含处理空数据的功能。因为正好报数到m的人会被移除。所以应该存在一个计数器i,它用于数据的每步向后推移。计数器z,用于计算有效报数,因为推移到移除的人后,不会报数,所以z不会增加。当z达到m后,这个人报数到了,就会移除。同时应该警惕报数到m时i移动到了一个已移除的位置。所以程序应该先判断这个位置是否还有效,然后进行z的增加操作,这样能保证不会出现输出移除信息的情况。必须要保证对z和对z数据的操作,对应的是同一个人。

 

 

 
;