【约瑟夫环】

问题描述

约瑟夫问题是个著名的问题:N个人围成一圈,第一个人从1开始报数,报M的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。

通过链表解决(待更新)

通过数组模拟解决(待更新)

通过数学推导公式解决

思路

首先,我先剧透一下推导公式:

f(N,M)=(f(N−1,M)+M)%N
  • f(N,M)f(N,M)表示,N个人报数,每报到M时杀掉那个人,最终胜利者的编号
  • f(N−1,M)f(N−1,M)表示,N-1个人报数,每报到M时杀掉那个人,最终胜利者的编号

下面我们来模拟一下n=7,m=3时的场景:

表示7个人,他们先排成一排,假设每报到3的人被杀掉。
刚开始时,头一个人编号是1,从他开始报数,第一轮被杀掉的是编号3的人。
编号4的人从1开始重新报数,这时候我们可以认为编号4这个人是队伍的头。第二轮被杀掉的是编号6的人。
……
第六轮时,编号1的人开始重新报数,这时候我们可以认为编号1这个人是队伍的头。这轮被杀掉的是编号5的人。
下一个人还是编号为1的人,他从1开始报数,不幸的是他在这轮被杀掉了。
最后的胜利者是编号为4的人。

将表格当成数组,并翻译后:

  • f(1,3)f(1,3) :只有1个人了,那个人就是获胜者,他的下标位置是0
  • f(2,3)=(f(1,3)+3)%2=3%2=1f(2,3)=(f(1,3)+3)%2=3%2=1:在有2个人的时候,胜利者的下标位置为1
  • f(3,3)=(f(2,3)+3)%3=4%3=1f(3,3)=(f(2,3)+3)%3=4%3=1:在有3个人的时候,胜利者的下标位置为1
  • f(4,3)=(f(3,3)+3)%4=4%4=0f(4,3)=(f(3,3)+3)%4=4%4=0:在有4个人的时候,胜利者的下标位置为0
    。。。
  • f(7,3)=4;

通过上面的推导我们发现了很多共同点,总结起来就是f(N,M)=(f(N−1,M)+M)%N(N个人报数,每报到M时杀掉那个人,最终胜利者的编号)。

好了,公式也推的差不多了。没时间多说了,上代码:

  • 代码演示

代码1:

#include <iostream>
using namespace std;
int main()
{
	int n, k, x = 0;
	cout << "请输入总共人数:";
	cin >> n;
	cout << "请输入k,确定第几个人:";
	cin >> k;
	for (int i = 2; i <= n; i++)
	{
		x = (x + k) % i;
	}
	cout << "最后的幸存者是:" << x + 1 << endl;
	return 0;
}

运行结果如下:
在这里插入图片描述

代码2

#include<iostream>
#include<stdio.h>
using namespace std;

int yuesefu(int n, int m)
{
    if(n == 1)
	{    //这里返回下标,从0开始,只有一个元素就是剩余的元素0
		return 0;
    }
    else
	{
		return (yuesefu(n - 1, m) + m) % n; 
    }
}
int main()
{
	int n, m;
	cout << "请输入总共人数:";
	cin >> n;
	cout << "请输入k,确定第几个人:";
	cin >> m;
	cout << "最后的幸存者是:" << yuesefu(n, m) + 1 << endl;
    return 0;
}

运行结果如下:

猜你喜欢

转载自blog.csdn.net/qq_41879343/article/details/89677017