约瑟夫环问题(圆桌问题)

约瑟夫环

约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队40余人,他们都是宁死不屈的人,所以不愿投降做叛徒。一群人表决说要死、所以用一种策略来先后kill所有人。于是约瑟夫建议:每次由其他两人一起kill一个人,而被kill的人的先后顺序是由抽签决定的,约瑟夫有预谋地抽到了最后一签,在kill了除了他和剩余那个人之外的最后一人,他劝服了另外一个没死的人投隆了罗马:
大致题意
在一间房间总共有n个人(下标O~n-1) ,只能有最后一个人活命。按照如下规则去清除人:

  • 所有人围成一圈
  • 顺时针报数,每次报到m的人将被清除掉被清除掉的人将从房间内被移走
  • 然后从被kill掉的下一个人重新报数,继续报数,报m的再清除,直到剩余一人

示例:

n=10,m=3,liv2=2   //live表示最终存活的人数
第3个人自杀,约瑟夫环编号为1
第6个人自杀,约瑟夫环编号为2
第9个人自杀,约瑟夫环编号为3
第2个人自杀,约瑟夫环编号为4
第7个人自杀,约瑟夫环编号为5
第1个人自杀,约瑟夫环编号为6
第8个人自杀,约瑟夫环编号为7
第5个人自杀,约瑟夫环编号为8
第10个人自杀,约瑟夫环编号为9
第4个人自杀,约瑟夫环编号为10

存活的人位置和约瑟夫环为:
所在位置: 4  约瑟夫环编号:10
所在位置: 10  约瑟夫环编号:9

请添加图片描述

解题思路

用一个数组和取模操作进行循环遍历,时间复杂度 O(n*k)

#include<bits/stdc++.h>
using namespace std;
#define MAX_SIZE 1001
//约瑟夫环
//sum 总人数 k:计数  live:存活的人数
void yueshefu(int k,int sum,int live){
    
    
	int man[MAX_SIZE]={
    
    0};//标记数组 man[i]表示第i个人的自杀顺序为 man[i]
	int count=1;//用来计数	
	int i=0,pos=-1;
	while(count<=sum){
    
    
		do{
    
    
			pos=(pos+1)%sum;
			if(man[pos]==0)
				i++;
			if(i==k){
    
    
				i=0;
				break;
			}
		}while(1);
		man[pos]=count;//赋值
		printf("第%d个人自杀,约瑟夫环编号为%d\n",pos+1,man[pos]);
		count++;
	}
	cout<<"\n存活的人位置和约瑟夫环为:\n";
	
	live=sum-live;
	for(int i=0;i<sum;i++){
    
    
		if(man[i]>live)
			cout<<"所在位置: "<<i+1<<"  约瑟夫环编号:"<<man[i]<<endl;
	}
}
int main(){
    
    
	yueshefu(3,10,2);
}

猜你喜欢

转载自blog.csdn.net/mitongxue/article/details/127774554