前言
作为一个刚接触C语言的小白,我找了一个学过C语言的同学每天晚上给我出题,于是那天晚上第一次接触了约瑟夫环问题,当时感觉挺有意思的,第一反应是建立一个首尾相连的循环体来遍历,但因为不知道咋实现,因为那时候刚接触数组,感觉可以用数组来做,于是花了几十分钟在解决无数bug后终于能运行出结果了(具体代码和运行结果见后面),后来的后来又学了结构体和指针,终于可以实现我最终的想法了。(因为刚学C语言,文章中或代码出现的错误欢迎指正)
一、约瑟夫环是什么?
约瑟夫环问题是一个很经典的问题:n个人围成一个圈子,设置一个数字炸弹为m,n个人按顺序从1开始以++的方式报数,当某个人碰到m时淘汰,并由下一个人接着从1开始循环往复,直到只剩下最后一人,求出最后一人是谁就是约瑟夫环问题的主题。用代码实现这个问题的求解,主要是要实现“循环”。
二、两种方法
1.数组的方法
这种思路一般不容易想到,但想到后思路就比较简单。我的大致思路是假如有n个人参与游戏,给每个人编号为1,2,3...n,n个人游戏最多进行n-1轮就能结束,因此笨笨的我建立了一个n*(n-1)大小的数组来实现游戏的循环,具体即为1,2,3,4...n,1,2,3,4...,n...然后通过for循环从数组第一位不断遍历,拿到炸弹的数字在整个数组中都变为0,谁拿到炸弹是根据一直遍历直到连续经过m个不为0的数字,最后经过(n-1)轮就能得出最后的答案。
代码如下(示例)
//
// Created by xsywan4520 on 2023/3/17.
//
#include <stdio.h>
#include <stdlib.h>
int main() { //定义变量n为游戏人数,x为数字炸弹,arr为总数组
int n, x=4;
printf("请输入游戏人数和数字炸弹的数字:");
scanf("%d,%d", &n, &x);
//首先创建一个n*(n-1)大小不断循环的数组,如当n=5,x=3时,arr[]={1,2,3,4,5,1,2,3,4,5}
int *arr= calloc(n*(n-1),sizeof(int));
if (!arr){return -1;}
for (int i = 0; i < n; i++) { for (int j = 0; j < n - 1; j++) { arr[i + j * n] = i + 1; }}
//定义num为游戏局数,i为流转次数,d为连续流转时未碰到炸弹的次数,当有人拿到炸弹时d重置为0,temp记录当时被淘汰人的姓名
int i = 0,d = 0, temp,num=0;
for (; i < n * (n - 1); i++) {
if (arr[i] != 0)d += 1;
if (d == x) {
num+=1;
temp = arr[i];
//对拿到炸弹被淘汰的进行输出
printf("淘汰的第%d个人为:%d",num,arr[i]);
for (int k = 0; k < n * (n - 1); k++) { if (arr[k] == temp)arr[k] = 0; }
d=0;
printf("\n");
if(num==n-1)break;}}
//最后对结果进行输出
for (int h=0; h < n * (n - 1); h++) {if(arr[h]!=0){printf("最终的获胜者为:%d",arr[h]);
free(arr);arr=NULL;return 0;}}
}
运行结果如下(实例)
总结
第二种方法有时间再写,不说了,两年半,呸,两点半了顶不住了,欢迎指正。