约瑟夫环问题
已知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;
}