约瑟夫环问题

约瑟夫环问题

约瑟夫环问题
首先,让n个小朋友们围成一个大圈。然后,随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数….这样下去….直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)。
不妨设结果为: f(n,m). f ( n , m ) .
先给出递推公式:
f(n,m)={[f(n1,m)+m]%nn>1;0n=1; f ( n , m ) = { [ f ( n − 1 , m ) + m ] % n n > 1 ; 0 n = 1 ;
下面推导如何得到这个递归公式:
初始序列 X X 为:
0,1,,n1.
不妨设第一次唱歌的小朋友的编号为: k=(m1)%n, k = ( m − 1 ) % n , 该小朋友出列,剩下的 n1 n − 1 个小朋友的序列 X X ′ 如下:
0,,k1,k+1,,n1. 0 , ⋯ , k − 1 , k + 1 , ⋯ , n − 1.
由于下一个小朋友(编号为 k+1 k + 1 )又从0开始报数,将原来编号为 k+1 k + 1 的小朋友的编号设为0,后面的依次相加,则新的编号序列 X′′ X ″ 为:
nk1,,n2,0,,nk2. n − k − 1 , ⋯ , n − 2 , 0 , ⋯ , n − k − 2.
设初始序列 X X 中的最后一个小盆友的编号为f(n,m),序列 X X ′ 的最后一个小朋友的编号为 f(n,m) f ′ ( n , m ) ,显然会有: f(n,m)=f(n,m) f ( n , m ) = f ′ ( n , m )
我们将序列 X X ′ 映射到序列 X′′ X ″ ,做线性映射:
XX′′:p(x)=(xk1)%n. X ′ ⟶ X ″ : p ( x ) = ( x − k − 1 ) % n .
显然逆映射为:
X′′X:p1(x)=(x+k+1)%n. X ″ ⟶ X ′ : p − 1 ( x ) = ( x + k + 1 ) % n .
而序列 X′′ X ″ 也可以看作:
0,1,,n2. 0 , 1 , ⋯ , n − 2.
因此序列 X′′ X ″ 的最后一个小盆友的编号为 f(n1,m). f ( n − 1 , m ) .
由此可以得到关系式子:
f(n,m)=f(n,m)=p1(f(n1,m))=[f(n1,m)+k+1]%n=[f(n1,m)+m]%n. f ( n , m ) = f ′ ( n , m ) = p − 1 ( f ( n − 1 , m ) ) = [ f ( n − 1 , m ) + k + 1 ] % n = [ f ( n − 1 , m ) + m ] % n .
推导完毕。
下面给出具体算法代码:

int JosephRing(int n, int m) {
    if(n < 1 || m < 1) return -1;
    int last = 0;
    for(int i = 2; i <= n; ++i) {
        last = (last + m) % i;
    }
    return last;
}

主要参考了《剑指Offer》

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值