约瑟夫环问题


一、问题描述

  设编号为1,2,3,……,n的n(n>0)个人按顺时针方向围坐一圈,m为任意一个正整数。从第一个人开始顺时针方向自1起顺序报数,报到m时停止并且报m的人出列,再从他的下一个人开始重新从1报数,报到m时停止并且报m的人出列。如此下去,直到所有人全部出列为止。要求设计一个程序模拟此过程,对任意给定的m和n,求出出列编号序列。

二、实现思路

  本程序采用顺序表来实现约瑟夫环问题,求出出列编号序列。顺序表的结构体类型中含有data[MaxSize]、length,数组元素的值为每个人在约瑟夫环中的排序,length存放当前约瑟夫环中的人数。其中,定义顺序表基本运算函数CreateSqList(PSqList &L, int n)、ListDelete(PSqList &L, int i),分别用来建立顺序表、删除顺序表第i个元素。另外,约瑟夫序列算法的具体实现用函数Josephus(PSqList &L, int k, int m)来实现。在该函数中,将逻辑序号转换为物理序号,再利用公式kl = (kl + m - 1) % i()来求出出列人的物理序号即数组下标,删除出列的数组元素,直到数组元素全部都出列。

三、解题代码

#include<iostream>
#include<malloc.h>
#define MaxSize 200					//约瑟夫环人数上限
using namespace std;

typedef int ElemType;

/*声明顺序表结构类型*/
typedef struct 
{
	ElemType data[MaxSize];			//存放编号的数组
	int length;						//当前约瑟夫环中的人数
}SqList, *PSqList;


/*建立顺序表*/
void CreateSqList(PSqList &L, int n)
{
	L = new SqList;
	int i = 0;
	while (i < n)
	{
		L->data[i] = i + 1;		//将每个人的逻辑序号的值存放到数组中
		i++;
	}
	L->length = n;				//存放约瑟夫环的人数

}

/*删除顺序表第i个元素*/
bool ListDelete(PSqList &L, int i)
{
	if (i<1 || i>L->length + 1)				//参数i错误时返回false
	{
		cout << "提供的删除位置i不合法!";
		return false;
	}
	i--;									//将顺序表逻辑符号转换为物理序号
	for (int j = i; j < L->length; j++)
	{
		L->data[j] = L->data[j + 1];
	}
	L->length--;
	return true;
}

/*约瑟夫序列算法*/
void Josephus(PSqList &L, int k, int m)
{
	int kl = k - 1;						//kl为第k个人的数组下标
	cout << "约瑟夫环的出列编号序列:";
	for (int i = L->length; i > 0; i--)
	{
		kl = (kl + m - 1) % i;			//出列人的物理序号即数组下标
		cout << L->data[kl] << " ";
		ListDelete(L, kl + 1);			//删除出列的数组元素
	}
}

int main() 
{
	PSqList L = NULL;				//创建约瑟夫环
	int n = 0;						//环中人数
	int m = 0;						//出列间隔
	int k = 0;						//起始序号
	cout << "请输入约瑟夫环的环中人数:";
	cin >> n;
	cout << "请输入约瑟夫环的出列间隔:";
	cin >> m;
	cout << "请输入约瑟夫环的起始序号:";
	cin >> k;
	CreateSqList(L, n);				//建立顺序表
	Josephus(L, k, m);				//约瑟夫序列算法
	return 0;

}

四、运行结果

  在约瑟夫序列算法的具体函数Josephus(PSqList &L, int k, int m)中,for循环每次使顺序表的长度减1,直到其为0,执行次数为约瑟夫环中的人数n,则该函数的时间复杂度为O(n)。另外,定义了变量kl,k,m,则空间复杂度为O(1)。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值