约瑟夫环的数学描述:
n个人{1,..,n},从1开始报数,报到m的退出,剩下的人继续从1开始报数。求最后一个人。
第一步,先把序号转换成数学好计算的表述,n个人{0,..,n-1} ,从0开始报数,报到m-1的人退出。
第二步,先将问题简化, 如果报数后第m个人不退出,第m+1个人从1开始报数。在这种假设的情况下,我们通过这种方法观察该事件发生后,人员座次的变化。
X' 是旧环的座次, X是新环的座次。则: Xn
= X'(n+m)/n (1式)
第三步, 添加条件,假设 t 是选定的最终座次号,用户那么每轮报数后 座次号的变化,可用表达式: Xt = X'(t'+m)/n (2式) , t'' 是 旧的座次号。
第四步,添加条件,假设每轮报数后,减掉一个人,即减掉座次为m-1的那位。但因为t是最终的获胜者,因此始终不会被淘汰掉,因此X t =X (t'+m)/n 的特性不变。现在归纳数列:
t n = (t n-1 +m )/n
t 1 = 0
附 约瑟夫还的代码 :
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int simple_josephus_1(int n, int m) {
if (n == 1) return 0;
return (simple_josephus_1(n-1, m) + m) % n;
}
int simple_josephus_2(int n, int m) {
char *ring = malloc(n);
memset(ring, 1, n);
int t = 0, i = 0, k = 0;
do{
if (ring[t]) k++;
if (k == m) {
k = 0;
ring[t] = 0;
i ++;
if (i == n) return t;
}
t = (t+1) % n;
} while (1);
return t;
}
int main(int argc, char *argv[]) {
int conv_tmp = 0;
char *arg_num = NULL;
char *arg_end = NULL;
size_t arg_len = 0;
int def_num = -1;
int number = 0;
int interleave = 0;
int left = 0;
if (argc != 3)
goto param_err;
arg_len = strlen(argv[1]);
arg_num = argv[1];
number = strtol(arg_num, &arg_end, 0);
if ((*arg_end != '/0' && arg_num[0] != '/0')|| (number <= 0))
goto param_err;
if (number <= 0) goto param_err;
arg_len = strlen(argv[2]);
arg_num = argv[2];
interleave = strtol(arg_num, &arg_end, 0);
if ((*arg_end != '/0' && arg_num[0] != '/0')|| (number <= 0))
goto param_err;
if (interleave <= 0) goto param_err;
left = simple_josephus_1(number, interleave) + 1;
printf("1, The left number is %d /n", left);
left = simple_josephus_2(number, interleave) + 1;
printf("2, The left number is %d /n", left);
param_err:
printf("You must give tow positive integers first represents ring's numbers anoth is interleave number! /n");
}