约瑟夫问题,注释详解

  Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

#include <stdio.h>
#define N 1000		//为计算的上限值


/*
2020-10-15
  Josephus有过的故事:39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓。于是决定了自杀
方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀。然后下一个重新报数,直到所有人都自杀身亡
为止。然而Josephus 和他的朋友并不想遵从,Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是
逃过了这场死亡游戏。

说明:输入需要计算的总人数n,通过数组来装对应的数字,每第三个就将对应值清零,当到最后一个值时,将已经清零的数组去掉,
每去掉一个数字,总数n减1。当全部排好后,再进行重复计算,直至n小于3时退出。

变量声明:i,j用于循环 ,zhi用于指向计数,即1,2,3,当等于3时就自杀,sign用于指向最后一个数时的标志位,
		  pai[i]用于存放序号的数组,n为计算的人数

*/
void main() {

	int n,i,j,zhi=0,sign = 0;
	int pai[N];

	printf("请输入多少个人,小于%d\n",N); //需要计算多少人
	scanf_s("%d", &n);

	//将序号写入
	for (i = 0; i < n; i++)
		pai[i] = i + 1;

	//去除
	for (i = 0; i < n; i++)
	{
		if (n < 3)  //退出条件
			break;

		zhi++;   //循环一次指向加1

		if (sign == 1)   //用于指向最后时,将i重置为0,因为即使最后i已经赋回0,但回到for循环时,i又会回到1,所以需要这步
		{
			i = 0;
			sign = 0;
		}
		if (zhi==3 && pai[i] != 0)  //当标志为3时,把当前指向的数组清0
		{
			pai[i] = 0;
			zhi = 0;
		}
		if ((i == n - 1) && n >= 3)  //此时指向最后一个数,且总数大于等于3
		{
			for (i = 0; i < n; i++) //循环找出是0的数,去掉
			{
				if ((pai[i] == 0)&& (i!=n-1))
				{
					for (j = i; j < n - 1; j++)  //将0的位置去掉,然后数组前移
						pai[j] = pai[j + 1];
					n = n - 1;   //每去掉一个,总数-1
				}

				if ((pai[i] == 0) && (i == n - 1))  //若最后一个等于0,那么直接总数减1;
				{
					n = n - 1;					
				}				 
			}
			sign = 1;              //走完最后的标志位
			i = 0;			
		}
	}

	printf("最后活下来的是%d %d", pai[0], pai[1]);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值