约瑟夫环:设编号为1,2,…n的n个人围坐一圈,约定标号为k的人从1考试报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止

题目:
(约瑟夫环)
设编号为1,2,…n的n个人围坐一圈,约定标号为k(1<=k<=n)的人从1考试报数,数到m的那个人出列,他的下一位又从1开始报数,数到m的那个人又出列,依次类推,直到所有人出列为止,由此产生一个出队编号的序列(或者求最后剩余的一个人)。

常用的有三种解法1-数组、2-循环列表、3-递归。

第一种解法:用数组来对约瑟夫环求解。
思路:定义一个数组,给其开辟空间,然后将编号放进数组中,即对数组初始化,遇到第k个则把第k个删除,将之后的元素向前移位。具体程序如下:

void Ysf_Cirle(int *space, int m, int k)
{
	for(int i=0; i<m; ++i)   //初始化
		space[i] = i+1;

	int pos = 0;
	while(m > 1)
	{
		for(int j=0; j<k-1; ++j)
			pos = (pos+1) % m;   //在此处求模,这样就可以达到循环的目的。
		cout<<space[pos]<<" ";   //若只求最后一个人,则屏蔽掉该句
		for(int n=pos; n<m-1; ++n)   //元素向前移位处理
			space[n] = space[n+1];
		m--;
	}
	cout<<space[pos]<<endl;
}

int main()
{
	int *space;
	int m, k;
	cout<<"input 人数:>";
	cin>>m;
	cout<<"input 间隔:>";
	cin>>k;

	space = (int*)malloc(sizeof(int)*m);
	Ysf_Cirle(space, m, k);
	free(space);
	return 0;
}

第二种解法:用循环链表来解。
思路:用现成的STL里面的链表,建立循环链表的环,随后将编号放进该环中,随后用迭代器定义出pos是起始位置。随后进行循环,遇到第k个节点删除,直至链表中剩余一个节点(注:在这块的难点在于,循环链表和迭代器定义的头节点中是没有编号的,因为我们每次循环的时候要跳过pos头结点)。具体程序如下:(#include)

void Ysf_Cirle(int m, int k)
{
	//建立循环链表的环
	list<int> mylist;
	for(int i=1; i<=m; ++i)
	{
		mylist.push_back(i);
	}

	//
	list<int>::iterator pos = mylist.begin(); //pos是起始位置
	while(mylist.size() != 1)
	{
		for(int j=0; j<k-1; ++j)
		{
			pos++;
			if(pos == mylist.end()) //跳过头结点
				pos++;
		}
		cout<<*pos<<" ";   //若只求最后一个人,则屏蔽掉该句
		pos = mylist.erase(pos);
		if(pos == mylist.end())  //跳过头结点
			pos++;
	}
	cout<<*pos<<endl;
}

int main()
{
	int m, k;
	cout<<"input 人数:>";
	cin>>m;
	cout<<"input 间隔:>";
	cin>>k;

	Ysf_Cirle(m, k);
	return 0;
}

第三种解法:递归

现在假设m=10

0 1 2 3 4 5 6 7 8 9 k=3

第一个人出列后的序列为:
0 1 3 4 5 6 7 8 9
即:3 4 5 6 7 8 9 0 1(*)

我们把该式转化为:
0 1 2 3 4 5 6 7 8 (**)

则你会发现: ((**)+3)%10则转化为(*)式了

也就是说,我们求出9个人中第9次出环的编号,最后进行上面的转换就能得到10个人第10次出环的编号了
设f(m,k,i)为m个人的环,报数为k,第i个人出环的编号,则f(10,3,10)是我们要的结果
当i=1时, f(m,k,i) = (m+k-1)%m
当i!=1时, f(m,k,i)= ( f(m-1,k,i-1)+k )%m
所以程序如下:

int fun(int m,int k,int i)
{
    if(i==1)
        return (m+k-1)%m;
    else
        return (fun(m-1,k,i-1)+k)%m;
}
int main(int argc, char* argv[])
{ 
    for(int i=1;i<=10;i++)
        printf("第%2d次出环:%2d\n",i,fun(10,3,i));
    return 0;
}
发布了57 篇原创文章 · 获赞 28 · 访问量 4148

猜你喜欢

转载自blog.csdn.net/weixin_41747893/article/details/99337212
今日推荐