约瑟夫环(joseph环)

约瑟夫环(joseph环)——经典算法

由多个玩家围成一个圈从一号玩家开始按顺时针杀掉下一名玩家,直到剩下最后一名,则该玩家获胜

对于此问题我们可以用一维数组的思想模拟出解法
数组思想
代码如下:

#include<iostream>
using namespace std;
#define H 10005
int a[H];
int main()
{
	int  d = 1, n, i;
	int c = 1;
	cout << "请输入参加游戏人数:" << endl;
	cin >> n;
	cout << "依次出局的编号为:";
	while (c <= n)
	{
		for (i = d; i < 2 + d; i++)
		{
			if (i > n) { i -= n; d -= n; }
			if (a[i])d++;
		}
		i--;
		cout << i << " ";
		a[i] = 1;
		d = i + 1;
		c++;
	}
	cout << endl << "最后获胜的玩家是:" << i;
}

请添加图片描述

核心代码:

for (i = d; i < 2 + d; i++)
		{
			if (i > n) { i -= n; d -= n; }
			if (a[i])d++;
		}
		i--;
		cout << i << " ";
		a[i] = 1;
		d = i + 1;
  • i:作为指针指向玩家。d:作为每次被淘汰的下一位玩家(可以理解为从d号玩家开始算起),d的初始值设为1。
  • f (i > n) { i -= n; d -= n; }检测下标,若超出范围将下标id跳转为1号玩家。
  • if (a[i])d++;判断该玩家如果被淘汰(若为则未淘汰,反之淘汰)将i的循环次数多加一次(当作跳过该玩家)。
  • i--;为了辅助for (i = d; i < 2 + d; i++)该循环在结束循环后会移动到被淘汰玩家的后一位玩家,为了避免这种错误,在打印淘汰者前会向前退一位。
  • a[i]=1;将该玩家判定为被淘汰状态。
  • d=i+1;移动到被淘汰的下一位玩家。

约瑟夫环——变种算法

编号是1,2,……,n的n个人按照顺时针方向围坐一圈,一开始任选一个正整数作为报数上限值m(m<n),从第s(s<n)个人开始沿顺时针方向自1开始顺序报数,报到m时停止报数。报m的人出列,将他的编号作为新的m值,从他在顺时针方向的下一个人开始重新从1报数,如此下去,直到所有人全部出列为止

该问题与经典约瑟夫环的不同就是上限从2变为任意并且开始编号从1号变为任意
所以我们只需要在基础算法上多定义一个上限值初始编号即可。
代码如下:

#include<iostream>
using namespace std;
#define H 10005
int a[H];
int main()
{
	int count, d,n,i;
	int c=1;
	cout << "请输入参加游戏人数:" << endl;
	cin >> n;
	cout << "请输入第一次的上限为多少:" << endl;
	cin >> count;
	cout << "请输入从几号开始:" << endl;
	cin >> d;
	cout << "依次出局的编号为:";
	while (c<=n)
	{
		for ( i = d; i < count+d; i++)
		{
			if (i > n) { i -= n; d -= n; }
			if (a[i])count++;
		}
		i--;
		cout << i << " ";
		a[i] = 1;
		count = i;
		d = i + 1;
		c++;
	}
}

count:为每次的上限值。(上限初始值为玩家输入)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值