约瑟夫环问题有多种解法,例如穷举法,或者采用链表法。
一、穷举法。设置一个N位的标志位数组,用以标志该位置是否已经出列。每出列一个位置,则将该标志位置位。当所有位置都置位时,则循环结束。
#include <iostream>
#include <bitset>
using namespace std;
#define N 7
#define M 3
int G_josephus_ring[N] = {8, 3, 6, 4, 1, 5, 2};
int G_josephus_output[N] = {0};
bitset<N> G_josephus_flag(0);
int main()
{
int cur_pos = 0;
int out_pos = 0;
int count = 1;
while(1){
cur_pos = (cur_pos + 1) % N;
if(!G_josephus_flag.test(cur_pos)){
if(++count == M){
count = 0;
G_josephus_output[out_pos++] = G_josephus_ring[cur_pos];
G_josephus_flag.set(cur_pos);
if(G_josephus_flag.count() == N){
break;
}
}
}
}
for(int i = 0; i < N; ++i){
cout << G_josephus_output[i] << " ";
}
cout << endl;
return 0;
}
二、链表法。将序列构造成一个循环链表,并依次访问该链表。当某位置需要出列时,将该位置从循环链表里面删除,直到链表里面只有一个元素,则循环结束。
#include <stdio.h>
typedef int ElemType;
typedef struct _node{
ElemType data;
struct _node *next;
}Node;
int main()
{
Node node1, node2, node3, node4, node5, node6, node7;
Node *preNode = NULL;
Node *curNode = NULL;
int count = 1;
node1.data = 8;
node1.next = &node2;
node2.data = 3;
node2.next = &node3;
node3.data = 6;
node3.next = &node4;
node4.data = 4;
node4.next = &node5;
node5.data = 1;
node5.next = &node6;
node6.data = 5;
node6.next = &node7;
node7.data = 2;
node7.next = &node1;
preNode = &node1;
curNode = preNode->next;
while(curNode->next != curNode){
if(++count == 3){
count = 0;
printf("%d ", curNode->data);
preNode->next = curNode->next;
}else{
preNode = curNode;
}
curNode = curNode->next;
}
printf("%d ", curNode->data);
return 0;
}
如果只要求最后的胜利者,则可以采用动态规划法,状态转移方程:
f(1) = 0; #只有一个人
f(n) = (f(n - 1) + M) % n;
如果采用递归法,则:
int Josephus(int n)
{
if(1 == n){
return 0;
}
return (Josephus(n - 1) + M) % n;
}
也可不使用递归:
#include <stdio.h>
#define N 7
#define M 3
int G_josephus_ring[N] = {8, 3, 6, 4, 1, 5, 2};
int main()
{
int i;
int s = 0;
for (i = 2; i <= N; ++i)
{
s = (s + M) % i;
}
printf ("\nThe winner is %d\n", G_josephus_ring[s]);
return 0;
}