您的位置:首页 > 其它

约瑟夫

2015-10-27 20:27 218 查看
约瑟夫问题源于一个犹太人的故事,相传在罗马入侵的时候,犹太人决定宁死不降,于是决定了一个自杀方式,所有41个人排成一个圆圈,从第一个人开始报数每报数到3人,这个人就得自杀,然后再由下一个人重新报数。直到剩下最后一个人自杀。Josephus和他的朋友不想自杀,所有他想出了一个方法,将自己与朋友安排在了巧妙的位置上,从而躲过了自杀。编写一个程序,计算出他们的位置。

分析:如果他们两个人想活下来,那么他们两个必须是最后两个自杀的人,因为前面的人都死了,他们就可以不遵守约定了,问题可以抽象成一个环形数列,从1号数字开始往后数,每次数到3的数字取出,从下一个数字重数。我们可以用一个环形链表来表示所有人所围成的圈,设置一个变量count记录已经自杀的人数,要求出最后两个人的位置,则需要count<<39。

#include<iostream>

using namespace std;

class josephusnode{

public:
 josephusnode(){
 this->alive=1;
 this->next=NULL;
 }
 ~josephusnode(){}
 bool isalive(){
 if(this->alive==1)
 return true;
 else 
 return false;
 }
 void killman()
 {
 this->alive=0;}
 josephusnode*getnext()
 {
 return this->next;}
 void setnext(josephusnode*node){
 this->next=node;
 }

private:
int alive;//alive变量,为1表示这个人还活着,否则已自杀
josephusnode*next;//指向下一个结点

};

class josephuscircle{

public:
josephuscircle(int n,int m){//判断输入是否合法
if(n<=0||n<m||m<=0)
{
cout<<"无效的人数"<<endl;
return;
}
this->length=0;
first=new josephusnode();
this->length++;
josephusnode*p=first;
for(int i=1;i<n;i++)//循环添加结点
{
josephusnode*node=new josephusnode();
p->setnode(node);
p=node;
this->length++;
}
p->setnode(first);
}

~josephuscircle(){//循环删除各个结点

josephusnode*p=this->first;
while(p->getnext()!=first){
josephusnode*temp=p;
p=p->getnext();
delete temp;
}
delete p;//删除尾结点
delete first;//删除头结点
}
josephusnode*getfirst()
{
return first;
}

private:
int length;
josephusnode*first;

};

void josephus(int n,int m,int number,josephuscircle*jose)

{
int josecount=0;//记录死亡的人数
int i=0;//记录报的数
josephusnode*p=jose->getfirst();//获取环的头结点
while(josecount<(n-number))//n-number表示需要死亡的总人数
{
do
{
if(p->isalive())//如果该结点活着
i++;//继续报数
if(i==m)//如果有人报到死亡数字
{
i=0;//报数归0,准备让下一个重新报数
p->killman();//该结点自杀
break;
}
p=p->getnext();
}while(1);
josecount++;//死亡人数//
}
int *alivepos=new int[number];//记录活着的人的位置的数组//
for(int index=0;index<number;index++)
alivepos[index]=0;//初始化数组//
p=jose->getfirst();
int pos=0;
int j=0;//记录活着的人的排列位置//
while(p->getnext()!=jose->getfirst())//遍历寻找活着的人//
{
if(j<number)
{
pos++;
if(p->isalive())//发现活着的人,将其位置填入数组//
{
alivepos[j]=pos;
j++;
}
p=p->getnext();
else
break;
}
}
if(p->alive()||j<number)
alivepos[j]=pos+1;//检查尾结点是否活着//
cout<<"能够活着的排列位置为:"<<endl;
for(int k=0;k<number;k++)
cout<<alivepos[k]<<"";//输出活着的人de位置//
cout<<endl;

}

int main()
{
cout<<"请输入参加约瑟夫游戏的总人数、死亡人数和需要活着的人数:"<<endl;
int n,m,number;
cin>>n>>m>>number;
josephuscircle*jose=new josephuscircle(n,m);
josephus(n,m,number,jose);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: