关于约瑟夫环的数学解法

约瑟夫环的数学描述:
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");
}

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值