约瑟夫环问题
已知n个人(以编号1,2,3….分别表示)围坐在一张圆桌周围,从编号为K的人开始报数,数到m个那个人出列;他的下一个人又从K开始报数,数到m的那个人又出列,以此规律重复下去,直到圆桌周围的人全部出列。
方法一:用链表实现
typedef struct LNode
{
int data;
struct LNode* link;
}LNode;
void jos1(int n,int k,int m)
{
LNode *p,*curr,*r;
p=(LNode*)malloc(sizeof(LNode));
p->data=1;
p->link=p;
curr=p;
for(int i=2;i<=n;i++)
{
LNode* s=(LNode*)malloc(sizeof(LNode));
s->data=i;
s->link=curr->link;
curr->link=s;
curr=s;
}
while(--k)
{
r=p;
p=p->link;
}
while(n--)
{
for(int s=m-1;s--;r=p,p=p->link);
cout<<p->data<<"->";
r->link=p->link;
p=r->link;
}
}
方法二:用容器list实现
void jose2(int n,int m)
{
if(m<1 || n<1)
exit(-1);
unsigned int i=0;
list<int> numbers;
for(i=1;i<=n;i++)
numbers.push_back(i);
list<int>::iterator current=numbers.begin();
while(!numbers.empty())
{
for(int i=1; i<m; i++)
{
current++;
if(current==numbers.end())
current=numbers.begin();
}
cout<<*current<<"->";
list<int>::iterator next=++current;
if(next==numbers.end())
next=numbers.begin();
--current;
numbers.erase(current);
current=next;
}
}
void jose2_2(int n,int k,int m)
{
if(m<1 || n<1 ||k<1)
exit(-1);
unsigned int i=0;
list<int> numbers;
for(i=1;i<=n;i++)
numbers.push_back(i);
list<int>::iterator current=numbers.begin();
while(--k)
{
current++;
if(current==numbers.end())
current=numbers.begin();
}
while(!numbers.empty())
{
for(int i=1; i<m; i++)
{
current++;
if(current==numbers.end())
current=numbers.begin();
}
cout<<*current<<"->";
list<int>::iterator next=++current;
if(next==numbers.end())
next=numbers.begin();
--current;
numbers.erase(current);
current=next;
}
}
方法三:数学推导,不过只能求出最后的胜利者序号
f(n,m)={1 ,n=1
{[f(n-1,m)+m]%n ,n>1
*/
int jose3(int n,int m)
{
if(m<1 || n<1)
return -1;
int s=0;
for(int i=2;i<=n;i++)
s=(s+m)%i;
return s;
}
测试
#include<iostream>
#include<list>
using namespace std;
void main()
{
jos1(9,3,5);
cout<<endl;
jose2(9,5);
cout<<endl;
jose2_2(9,3,5);
cout<<endl;
cout<<jose3(5,3);
cout<<endl;
}