约瑟夫环问题有多种解法,例如穷举法,或者采用链表法。
一、穷举法。设置一个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; }