约瑟夫问题分为两种类型
类型一
约瑟夫问题如下:
n个人围成圈,依次编号为1,2,..,n,现在从1号开始依次报数,当报到m时,报m的人退出,下一个人重新从1报起,循环下去,问最后剩下那个人的编号是多少?
input:
amount 队列人数
m 数到m时退出一个人
output:
最后一个退出的人的下标
思路:(用布尔数组做)
我们可以把这amount个人想象成是都是true的布尔数组,然后每次有个人找true的数组,是的话就往前进,一直进m个然后进行下一次操作,进了m次之后把m次到达的位置置为false. 如此循环往复,直到数组中只剩一个true为止
我下面的代码就是参照上面思路来写的。
#include <iostream>
using namespace std;
bool trek[1000];
void main()
{
int amount,m;
cin>>amount>>m;
for(int i=1;i<=amount;i++){//对布尔数组赋初值
trek[i] = true;
}
int num=amount;
while(num!=1){ //数组只剩一个为true时退出
int temp=0,count=0;//temp记录m,count对数组进行遍历
while(1){
if(temp==m) { trek[count]=false;break;}
count++; //count位置很讲究,不放在这儿就错了
if(count>amount) count-=amount;//循环
if(trek[count]==true) temp++;
}
num--;
}
for(i=1;i<=amount;i++){ //输出
if(trek[i] == true)
cout<<i<<endl;
}
}
类型二
类型二的约瑟夫问题就是在类型一的基础上修改了一点点,类型一是每次都是从1位置开始数,而类型二是每次从上一次之后的下一个位置开始数,因此类型二与类型一的代码大同小异。
在代码中计数是通过count变量完成的,而在类型一中每次找到一个就对count进行了重置,在类型二中代码只许不对count进行重置即可
代码如下:
#include <iostream>
using namespace std;
bool trek[1000];
void main()
{
int amount,m,count=0; //count在此处声明
cin>>amount>>m;
for(int i=1;i<=amount;i++){
trek[i] = true;
}
int num=amount;
while(num!=1){
int temp=0; //类型二中的count没有在此处重置
while(1){
if(temp==m) { trek[count]=false;break;}
count++;
if(count>amount) count-=amount;
if(trek[count]==true) temp++;
}
num--;
}
for(i=1;i<=amount;i++){
if(trek[i] == true)
cout<<i<<endl;
}
}