约瑟夫环(Josephus Circle)

目录

一、问题描述

二、用数组求解

三、用递归求解 



一、问题描述

约瑟夫环(Josephus Circle)是一个数学的应用问题:已知 n 个人(分别用编号 0, 1, 2, ..., n - 1 表示)围坐在一张圆桌周围。从编号为 0 的人开始报数,数到 m 的那个人出圈,他的下一个人又从 1 开始报数,数到 m 的那个人又出圈,依次规律重复下去,直到剩余最后一个胜利者。例如,有 10 个人围成一圈进行此游戏,每个人的编号为 0 ~ 9,规定数到 3 的人出圈,则游戏过程如下所示:

  1. 0,1,[2],3,4,5,6,7,8,9

  2. 0,1,[2],3,4,[5],6,7,8,9

  3. 0,1,[2],3,4,[5],6,7,[8],9

  4. 0,[1][2],3,4,[5],6,7,[8],9

  5. 0,[1][2],3,4,[5][6],7,[8],9

  6. [0][1][2],3,4,[5][6],7,[8],9

  7. [0][1][2],3,4,[5][6][7][8],9

  8. [0][1][2],3,[4][5][6][7][8],9

  9. [0][1][2],3,[4][5][6][7][8][9]

所以出圈的顺序是:2,5,8,1,6,0,7,4,9。最终剩下 3 号,3 号是胜利者。

二、用数组求解

#include <stdio.h>

#define N 100000  // 最大数

// 用一维数组 is_out 来标识这 N 个人的状态,0 表示没有出圈,1 则表示出圈了。
int is_out[N] = { 0 };  

int main()
{
	int n = 0;  // 游戏参与的人数
	int m = 0;  // 数到 m 时出圈
	scanf("%d%d", &n, &m);
	int count = 0;  // 出圈的人数
	int num = 0;  // 报数器,当报到数字 m 时出圈
	int i = 0;  // 从编号为 0 的人开始报数
	// 一、淘汰 n - 1 个人
	while (count < n - 1)  
	{
		if (is_out[i] == 0)  // 未出圈的人报数
		{
			num++;  
			if (num == m)  // 报到数字 m 的人出圈
			{
				printf("%d ", i);
				is_out[i] = 1;
				count++;
				num = 0;  // 有人出圈后,报数器重置为 0
			}
		}
		// i = (i + 1) % n;  // i + 1,并保证 i 的取值范围是:0 ~ n-1
		// 或者:
		i++;
		if (i > n - 1)
			i = 0;
	}
	printf("\n");
	// 二、输出胜者的编号
	for (i = 0; i < n; i++)
	{
		if (is_out[i] == 0)
			printf("The winner is %d\n", i);
	}
	return 0;
}

 

三、用递归求解 

定义递归函数:josephus(int n, int m, int i),它表示在有 n 人的圆桌中,报到数字 m,第 i 个人出圈的编号

第 1 个人出圈的编号是 (m - 1) % n,因为编号从 0 开始,且有 m <= n 和 m > n 的两种情况

当第 i 个人出圈后,剩下的 n - i 个人就组成了新的约瑟夫环

#include <stdio.h>

int josephus(int n, int m, int i)
{
	if (i == 1)
		return (m - 1) % n;
	else
		return (m + josephus(n - 1, m, i - 1)) % n;
}

int main()
{
	int n = 0;
	int m = 0;
	scanf("%d%d", &n, &m);
	int i = 0;
	// 淘汰 n - 1 个人
	for (i = 1; i < n; i++)
	{
		printf("%d ", josephus(n, m, i));
	}
	// 输出胜利者的编号
	printf("\n");
	printf("The winner is %d\n", josephus(n, m, i));
	return 0;
}

 

  • 15
    点赞
  • 40
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值