约瑟夫问题 递归解法

约瑟夫问题是个有名的问题:N个人围成一圈,编号由0到N-1,从第一个开始报数,第K个将出局,最后剩下一个人。例如N=6,K=5,出局人编号的顺序是:4,3,5,1,2,赢家是0。

这里给出一个十分简洁的递归解法:

#include <bits/stdc++.h>
int solve(int n, int k) {
    if (n == 1) return 0;
    else return (solve(n - 1, k) + k) % n;
}
int main() {
    int N, K;
    scanf("%d %d", &N, &K);
    printf("%d", solve(N, K));
    return 0;
}

理解:
solve(n,k)的意思是,有n人,以k为步长删人的约瑟夫问题的解。那么显然solve(1,k)=0,即只有1个人的时候,胜者就是编号为0的这一个人。

若不是1个人,有n人,删掉第k人(编号k-1)之后变成了n-1人,下次起始的地方是从这个出局的人后面开始算的,不妨把该开始位置的人编号“看成“0。
示意:

... [k-1 ] [ k ] [k+1] ...    // 删之前 即“先状态”
... [dele] [ 0 ] [ 1 ] ...    // 删之后 即“后状态”

那么若要从n-1个人的“后状态”恢复到“先状态”,其实所有人的编号相当于加k,亦即f[n] = f[n-1] + k,再由于是环的问题,所以加完再对"先状态时,即删前"人数n取模即可。

这里有个小地方要注意一下,每次取模的是当前游戏人数,可以稍微想想为啥?如果你写成迭代版本,以i为下标迭代,F[1]=0;F[i]=(F[i-1]+k)%i;这里是模i而非n,要留意。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • “有问题”是生活的一大内容。 有了互联网之后,生活上的各类问题,只要去找百度和Google就可以了。 而学习上遇到...
    月光画画阅读 874评论 0 50
  • 生活是一件严肃的事
    北七海阅读 181评论 0 0
  • 编者注:本文摘译自Close.io公司网站博客,译文有删改。内容不当之处请在Kuick微信公众号后台留言,获取更多...
    崔超阅读 410评论 0 0
  • 玲子姐是我们那活力充沛的妇女之友之一,近四十岁仍旧风韵犹存,生性大大咧咧,到哪都能打成一片。虽说离异,独自带着儿子...
    独立行走的鱼阅读 663评论 0 4
  • 如果说人是有灵性的,那么梦是不是也有感应?你走了一年半,是不是不放心你的儿子,你的孙子,才托梦给我? 你又一次出现...
    瞳瞳日中的微笑阅读 907评论 1 3