约瑟夫环
约瑟夫是犹太军队的一个将军,在反抗罗马的起义中,他所率领的军队被击溃,只剩下残余的部队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);
}