zoukankan      html  css  js  c++  java
  • 剑指offer---约瑟夫环问题

    参考文献:

    换个角度举例解决约瑟夫环

    约瑟夫环——公式法(递推公式)

    在刷leetcode的剑指offer时,做到这道关于约瑟夫环的题,首先自己是一脸懵逼的。这是啥玩意,看不懂啊。后来i仔细思考之后,想到用队列来解这道题,根据队列先进先出的特性这样就能循环解决这个问题。嗯,完美。说干就干。。。

    但是出现了一个尴尬的问题----现在我还不太会用队列。于是只能看看大佬的题解了,里面有用链表的有用队列的,看的我脑瓜子嗡嗡的,WTF.。但是,突然看到一个数学解法。一看,哎呦,不错哦。简单明了。但是,又但是了。因为确实看了很多遍,直到写这篇博客的时候还是有点迷糊。所以就打算记录一下这些点,以后再遇见能够好好研究研究。如果各位有什么好的见解以及本文存在的不足之处。欢迎各位指正批评。话不多说,看看关于大佬的思路。

    主要是看了这两篇文章:首先是这一篇:

    约瑟夫环——公式法(递推公式)

    这篇我觉得讲的很好,至少我这个小白算是看懂了,

    文中首先提到了什么是约瑟夫问题:然后给出了两种解决方案:

    • 普通解法:运用链表。
    • 公式法:

    公式法:

    约瑟夫环是一个经典的数学问题,我们不难发现这样的依次报数,似乎有规律可循。为了方便导出递推式,我们重新定义一下题目。
    问题: N个人编号为1,2,……,N,依次报数,每报到M时,杀掉那个人,求最后胜利者的编号。

    这边我们先把结论抛出了。之后带领大家一步一步的理解这个公式是什么来的。
    递推公式:

     用不同数字表示每个人:

                1、2、3、4、5、6、7、8、9、10、11

    表示11个人。排成一排假设每报道3的人被杀掉。

    • 刚开始时,头一个人编号是1,从他开始报数,第一轮被杀掉的是编号3的人。
    • 编号4的人从1开始重新报数,这时候我们可以认为编号4这个人是队伍的头。第二轮被杀掉的是编号6的人。
    • 编号7的人开始重新报数,这时候我们可以认为编号7这个人是队伍的头。第三轮被杀掉的是编号9的人。
    • ……
    • 第九轮时,编号2的人开始重新报数,这时候我们可以认为编号2这个人是队伍的头。这轮被杀掉的是编号8的人。
    • 下一个人还是编号为2的人,他从1开始报数,不幸的是他在这轮被杀掉了。
    • 最后的胜利者是编号为7的人。

    下图表示这一过程(先忽视绿色的一行)

     图中绿色部分表示的是这些数组成的数的下标:

    上边得到的公式描述的是:幸存者在这一轮的下标位置

    • f(1,3):只有1个人了,那个人就是获胜者,他的下标位置是0
    • f(2,3)=(f(1,3)+3)%2=3%2=1:在有2个人的时候,胜利者的下标位置为1
    • f(3,3)=(f(2,3)+3)%3=4%3=1:在有3个人的时候,胜利者的下标位置为1
    • f(4,3)=(f(3,3)+3)%4=4%4=0:在有4个人的时候,胜利者的下标位置为0
    • ……
    • f(11,3)=6

    上面这个例子验证了这个递推公式的确可以计算出胜利者的下标,下面讲解怎么推到这个公式。

    **问题1:**假设我们已经知道11个人时,胜利者的下标位置为6。那下一轮10个人时,胜利者的下标位置为多少?
    **答:**其实吧,第一轮删掉编号为3的人后,之后的人都往前面移动了3位,胜利这也往前移动了3位,所以他的下标位置由6变成3。

    **问题2:**假设我们已经知道10个人时,胜利者的下标位置为3。那下一轮11个人时,胜利者的下标位置为多少?
    **答:**这可以看错是上一个问题的逆过程,大家都往后移动3位,所以f(11,3)=f(10,3)+3。不过有可能数组会越界,所以最后模上当前人数的个数,f(11,3)=f(10,3)+3%11

    关于越界的解释如图中所示;图中讲的就是如何消除数组越界的问题。相信大家都看得懂:

    因此我们可以推出递推公式f(8,3) = [f(7, 3) + 3] %8。
    进行推广泛化,即f(n,m) = [f(n-1, m) + m]%m。

    **注:**理解这个递推式的核心在于关注胜利者的下标位置是怎么变的。每杀掉一个人,其实就是把这个数组向前移动了M位。然后逆过来,就可以得到这个递推式。

    文中最后说求出的结果是数组的下标,最终编号还要加1.但是我用C语言编写的结果不用加1直接返回结果也可以。

     

    1 int lastRemaining(int n, int m){
    2     int pos=0;
    3     for(int i=2;i<=n;i++)
    4     {
    5         pos=(pos+m)%i;
    6     }
    7     return pos;
    8 }

  • 相关阅读:
    CSP-S2019游记
    BZOJ4668 冷战
    [ZJOI2007]仓库建设
    CF833B The Bakery
    决策单调性优化DP+分治优化决策单调性
    穿越栅栏 Overfencing
    控制公司 Controlling Companies
    派对灯 Party Lamps
    CSP2019总结
    差分约束
  • 原文地址:https://www.cnblogs.com/sbb-first-blog/p/13632309.html
Copyright © 2011-2022 走看看