c语言相关的约瑟夫环问题

约瑟夫环问题,已知 50 个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。. 从编号为 1 的人开始报数,数到 n 的那个人出圈;他的下一个人又从 1 开始报数,数到 m 的那个人又出圈;依此规律重复下去,直到剩余最后一个胜利者。

#include 
int main(){
    int n,sz[50];
    for(int i=0;i<50;i++){
        sz[i]=i+1;
    }
    printf("请输入希望删除的序号:\n");
    scanf("%d",&n);
    int i=0;
    while(1){
        int num=0;//记录删除的元素个数 
        if(sz[i]!=0){
            if(i==n-1){
                sz[i]=0;
                //令计数重复新开始 
                i=-1;
            }
            i++;
        }
        //判断去掉元素个数,当个数达到四十九时退出循环。 
        for(int j=0;j<50;j++){
            if(sz[j]==0) num+=1;
        }
        if(num==49) break;
    }
    //输出剩下的数 
    for(int i=0;i<50;i++){
        if(sz[i]!=0) printf("%d ",sz[i]);
    }
    return 0;
}

无法退出循环

代码里有2个问题:

  • 在每次进行删除操作后,计数并没有重新从1开始,而是继续从上一次的位置开始。因此,如果当前要删除的元素的位置正好是删除操作之前的计数位置,那么计数会一直停留在这个位置,无法进行下一次删除。
  • 在删除操作中,如果当前要删除的元素的位置正好是删除操作之前的计数位置,由于计数器没有重置,会导致删除操作立刻结束,这会导致程序无限循环下去。

修改后的代码为:

#include <stdio.h>

int main() {
    int n, sz[50];
    for (int i = 0; i < 50; i++) {
        sz[i] = i + 1;
    }
    printf("请输入希望删除的序号:\n");
    scanf("%d", &n);

    int i = 0;
    while (1) {
        int num = 0; // 记录删除的元素个数
        if (sz[i] != 0) {
            if (i == n - 1) {
                sz[i] = 0;
                // 令计数重复新开始
                i = -1;
            }
            i++;
        }
        // 判断是否有要删除的元素
        int delete_flag = 0;
        for (int j = 0; j < 50; j++) {
            if (sz[j] == 0) {
                num += 1;
            } else if (j == n - 1) {
                delete_flag = 1;
            }
        }
        // 如果没有要删除的元素,则跳过删除操作,继续进行计数
        if (num == 49 || delete_flag == 0) {
            break;
        }
    }

    // 输出剩下的数
    for (int i = 0; i < 50; i++) {
        if (sz[i] != 0) {
            printf("%d ", sz[i]);
        }
    }
    return 0;
}