C语言 (编程题:约瑟夫环 报数游戏)

1.前言

最近有点emo,写博客也没有什么特别想写的内容 这篇博客把约瑟夫环用C语言来写一下 巩固一下原来学过的知识。

2.什么是约瑟夫环

这有个历史故事还是比较有意思的:据说著名犹太历史学家Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。
在这里插入图片描述

简而言之,这个问题概括就是:有41个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位?

3.算数分析问题

(以12个人举例进行画图分析)
在这里插入图片描述

正如同这张图所表示的:
第一次淘汰:从第一个人开始报数的时候3的倍数全部死亡
第二次淘汰:从上次死亡的后一位开始来进行从1开始的报数

…(循环上述的步骤)

直到最后判断是否剩下一个人,如果剩下一个人则结束。
在这里插入图片描述
经过四次循环 游戏结束 最终只剩下一位幸存者为第10位。

四.编程思想分析

(1)由于对于每个人只有死和活两种状态,我们可以对每个人的生命值进行赋值 存活为1,死亡为0。
(2)开始时每个人都是活的,所以数组初值全部赋为1
(3)循环前先判断剩余的幸存者是否大于1个
(4)如果出现淘汰的人下一个人从1开始重新开始计数

五.编程实现

函数原型:

int Josephus_problem(int n)//这里面的n为参与的总人数。

考虑到游戏人数由n传入,存储大小未定因此我们需要用到动态内存的知识,来定义一个动态数组给他们依次编号。

int* arr = (int*)malloc(n * sizeof(int)); 

因为在最初开始所有的人都是存活的所以就将数组初值赋为1代表存活。

for (int i = 0; i < n; i++)
	{
		arr[i] = 1;
	}

随着报数的不断进行,总人数肯定会不断减少,并且我们需要通过判断幸存人数来判断是否结束循环 所以我们引入一个变量tmp来代表剩余人数。

int tmp = n;//幸存人数

而且有一个关键性的变量,那就是各个玩家所报出来的数字,我们用这个数字来淘汰每个报数报到3的玩家,在这里我们将他命名为count。

int count = 0;//报的号

我们需要一个循环来进行报数操作,但是在循环前我们需要判断剩余人数是否为1,如果大于1才可以正常执行下列循环操作

while (tmp > 1)
	{
	
	}

判断完剩余人数后,进行循环,通过循环来进行报数操作并且完成每位成员依次报数与报到3就将他的生命值赋为0:

	for (int i = 0; i <n; i++)
		{
			if (arr[i] == 1)
			{
				count++;
				if (count == 3)
				{
					arr[i] = 0;
					tmp--;
					count = 0;
				}
			}
		}

最后加个判断 如果传入的人数为负值或者出现其他错误,直接返回-1相当于报错 我们也可以知道中途出现了错误。

for (int i = 0; i <n; i++)
	{
		if (arr[i] == 1)
		{
			return i;
		}
	}
	return -1;

六.完整代码及运行结果

#include<stdio.h>
#include<stdlib.h>

int Josephus_problem(int n)
{
	int* arr = (int*)malloc(n * sizeof(int));
	for (int i = 0; i < n; i++)
	{
		arr[i] = 1;
	}

	int tmp = n;//幸存人数
	int count = 0;//报的号

	while (tmp > 1)
	{
		for (int i = 0; i <n; i++)
		{
			if (arr[i] == 1)
			{
				count++;
				if (count == 3)
				{
					arr[i] = 0;
					tmp--;
					count = 0;
				}
			}
		}
	}
	for (int i = 0; i <n; i++)
	{
		if (arr[i] == 1)
		{
			return i;
		}
	}
	return -1;
}

int main()
{
	printf("%d\n", Josephus_problem(人数)+1);
	return 0;
}

运行结果:
以12人为例
在这里插入图片描述
与上面画图分析结果相同。

以41人为例
在这里插入图片描述

七.小结

对于约瑟夫环这个问题,最重要的就是将数学思维转换为C语言思维,最终运用代码表示出来;并且在编写代码的过程中还需要注意一些小的细节:需要用动态内存分配存储空间,还有学会运用变量这样可以使问题变得更加简便。

(如有问题,欢迎大佬指正)

  • 12
    点赞
  • 47
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mi ronin

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值