算法——The Josephus Problem

题目描述

The problem is named after Flavius Josephus, a Jewish historian who participated in and chronicled the Jewish revolt of 66-70C.E. against the Romans. Josephus, as a general, managed to hold the fortress of Jotapata for 47days, but after the fall of the city he took refuge with 40 diehards in a nearby cave. There the rebels voted to perish rather than surrender. Josephus proposed that each man in turn should dispatch his neighbor, the order to be determined by casting lots. Josephus contrived to draw the last lot, and as one of the two surviving men in the cave, he prevailed upon his intended victim to surrender to the Romans. Your task:computint the position of the survivor when there are initially n people.

输入

a Positive Integer n is initially people. n< = 50000

输出

the position of the survivor

样例输入

6

样例输出

5

代码

#include<iostream>
using namespace std;
int main(){
	int n;
	cin>>n;
	int s = 0;
	for(int i = 1; i <= n ; i++){
		s = (s + 2)%i;
	}
	cout<<s+1<<endl;
}

算法非常的巧妙,所以看起来很简单,oj 上是可以通过的哦~
我们再来看一下另一种形式的代码

#include<iostream>
#include<cstdlib>
using namespace std;
typedef struct{
	int num;
}save;
int Josephus(int n,save *a){ 
	int m = 1;
	save b[50001];
	if(n%2 == 0){
		int k = n/2;
		for(int i = 1;i <= n;i++){
			if(i == 2*k - 1){
				b[m++] = a[i];
			}
		}	
	}
	else{
		int k = n/2;
		for(int i = 1; i <= n; i++)
		if(i == 2*k + 1)
		{
			b[m++] = a[i];
		}
	}
	for( int i = 1; i < m ;i++){
		a[i] = b[i];
	}
	if (m - 1 ==1) {
		return a[m-1].num;
	}
	Josephus(m -1 , a);
} 
int main(){
	int n;
	cin>>n;
	save a[50001];
	for(int i = 1; i <=n ;i++){
		a[i].num = i;
	}
	cout<<Josephus(n,a)<<endl;;
	return 0;
}

在c++环境下运行是没有问题的,但是有些oj 上通过不了,一直报WrongAnswer,有没有大佬看看呢?

运行结果

在这里插入图片描述
数字太小了,那我们试一下32767(15个1)
在这里插入图片描述
运行结果都是一样的,但是第二种在oj 上通过不了/迷。

思路

第一种方法:
把情况分为奇数和偶数:
1.首先分析偶数:很容易发现,为了得到一个人的初始位置,我们只需要将它的新位置乘2并减去1。对幸存者来说,这个关系会保持下去,也就是:J(2k)=2J(k)-1;
2.再来分析奇数:为了得到新的位置编号相对应的初始位置编号,我们必须把新的位置乘2再加上1,因此,对于奇数我们有J(2k+1)=2J(k)+1;
这是反向替换法;
第二种方法:
在方法一的基础上进行改进,我们可以得到两个递推式的解的一个闭合式,有意思的是,关于闭合式的最优雅的形式涉及规模 n 二进制表示:我们可以对 n 本身做一次向左的循环来得到 J(n)!,例如,J(6)=J(110)2=(101)2=5。
这是前项替换法。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章