约瑟夫环 数学解法 f(n,k)=(f(n-1,k)+k)%n 公式讲解

问题:有n个人站成环 从1开始报数,报k的人去死,之后下一个人报1,问当你是第几个的时候可以活下来?

这篇文章主要是讲解  f(n,k)=(f(n-1,k)+k)%n 这个公式是什么意思为什么是对的

虽然公式是使用数学解法 但开始时我会手动的模拟过程 其是有意义的 十分有助于理解

首先我们看样一个问题

n=2, k=3

a b

我们首先使用人力来数 a b a 很好 a死

接下来在试一遍 n=2 k=4

a b

人力:a b a b 很好b死

n=2 k=5

人力 a b a b a 很好a死

n=2 k=9999999

人力:T_T

对于   a b 数到k死 其实用k%2就可以很快的知道谁会死了

为什么?

a b

设k=9 ab一共有两个  所以 9%2=1  意思就是abab的数,数完最后一次完整的循环后又数了1个(数到了a)  这正是取模%的意义

现在我们还是用手动模拟 n=11 k=3

这次不用字母而是用数字编号以直接返回生存者的编号(剧透 注意分别 第几个和编号的不同)

1 2  3 4 5 6 7  8 9 10 11

第1个死去的 k%n 即 3%11=3 第三个死去 因为我们从死去的下一个开始重新数1 也就是说 死去的下个(编号4)是新的环的开始 死去的上个(编号3)是新的环的结束

4 5 6 7 8 9 10 11 1 2 (这就是新的环)

规则就是这样 下面我会直接写到生存者出现

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

当当最后的幸存者是7

------完结撒花------

f(n,k)=(f(n-1,k)+k)%n这个公式到底描述的是什么呢?(怎么用?)

将上面表格的每一行看成数组 这个公式描述的是下一轮幸存者在这一轮的下标位置

f(n,k)求得值是 有n个人 数k死最后幸存的人的下标位置是几

这很明显是个递归的式子 需要从底到上的运算

最底端是 f(1,k) f(1,k)=0 就是说只有一个人的时候幸存者的下标是0(废话--) 编号是7

向上

f(2,k) =(f(1,k)+k)%n  在n=11 k=3是 f(2,3)=(f(1,3)+3)%2=3%2=1

在只剩两个人时 幸存者在这一轮数组中的下标位置是1  (看看上面的表格 下标位置为1 编号是7 )

向上

f(3,3)=(f(2,3)+3)%3=4%3=1

在只剩三个人时 幸存者在这一轮数组中的下标位置是1  (看看上面的表格 下标位置为1 编号是7 )

f(4,3)=(f(3,3)+3)%4=4%4=0

在只剩三个人时 幸存者在这一轮数组中的下标位置是0  (看看上面的表格 下标位置为0 编号是7 )

.

.

f(11,3)=(f(10,3)+3)%11=6%11=6  (看看上面的表格第一行 下标位置为6 编号是7 )

我们很容易可以根据式子写

1 int p=0;//结果
2 for(int i=2;i<=n;i++)
3 {
4     p=(p+k)%i;
5 }

p就是我们要求的第一轮的生存者的下标

而在第一轮中没有人死去(泪目..) 编号与下标的关系是编号=下标+1(数组从0开始存储)

所以完整的函数代码是

int cir(int n,int k)
{
    int p=0;
    for(int i=2;i<=n;i++)
    {
        p=(p+k)%i;
    }
    return p+1;
}

那么这个公式为什么是正确的呢?

当我们杀死一个一个人 并形成一个新环时 实质上是掉这个人并把整个环向前移动k位

1 2 3 4 5 6 7 8 9 10 11

  第一轮去掉3

1 2 4 5 6 7 8 9 10 11  

们从死去的下一个开始重新数1 也就是说 死去的下个(编号4)是新的环的开始 死去的上个(编号3)是新的环的结束 就是把编号4前移k(3)格使他成为新环开始

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

让我们在重申一遍f(n,k)=(f(n-1,k)+k)%n描述的是下标位置的变化

编号1的下标位置是0 0前移3格 下标位置变成-3 -3+11=8 所以在n轮下标位置为0的编号1在n-1轮中的下标位置变成了8

如果也有一个公式的话大概就是 f(n-1,k)=f(n,k)-k>=0?f(n,k)-k:f(n,k)-k+n;

那么从n-1轮的下标位置推算第n轮的下标位置就很清楚了 f(n,k)=f(n-1,k)+k>=n?f(n-1,k)+k%n:f(n-1,k)+k  (%n  使得f(n,k)取得的下标在n的范围之内)

f(n,k)=(f(n-1,k)+k)%n

以上

重点在于f(n,k)描述的是下标位置的变化

时间: 2024-10-08 01:28:21

约瑟夫环 数学解法 f(n,k)=(f(n-1,k)+k)%n 公式讲解的相关文章

约瑟夫环数学解法

#include<iostream>using namespace std;int fun(int n, int m){    int i, r = 0;    for (i = 2; i <= n; i++)         r = (r + m) % i;    return r+1;} void main(){    int i, m;    cin >> i >> m;    cout << fun( i, m );}

趣味算法--约瑟夫环问题

问题描述 已知n个人(以编号1,2,3,...,n分别表示)围坐在一张圆桌上.指定编号为k的人开始从1报数,数到m的那个人出列:出列那个人的下一位又从1开始报数,数到m的那个人出列:以此规则重复下去,直到圆桌上的人全部出列. 分析解决 解决方法主要有逻辑分析.数学分析法. 逻辑分析:就是按照游戏规则一个个报数,报到m的人出局,结构层次简单清晰明了.这种方式实现主要采用顺序表实现 数学分析:采用数学方式归纳统计分析出每次出局人的规律,直接得出每次出局的人,然后以代码实现.这种方法需要较强的数学分析

约瑟夫环的数学解法

CSDN链接 问题描述:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列:他的下一个人又从1开始报数,数到m的那个人又出列:依此规律重复下去,直到圆桌周围的人全部出列.求最后剩下的人的初始编号. 可以把问题转换成:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数.求胜利者的编号.则所得的解加1即为原问题的解: 一般我们采用一个循环队列来模拟约瑟夫环的求解过程,但是如果n比较大的时候,采用模拟的方

约瑟夫环问题的链表解法和数学解法(PHP)

约瑟夫环问题 一群猴子排成一圈,按1,2,-,n依次编号.然后从第1只开始数,数到第m只,把它踢出圈,从它后面再开始数,再数到第m只,在把它踢出去-,如此不停的进行下去,直到最后只剩下一只猴子为止,那只猴子就叫做大王.要求编程模拟此过程,输入m.n,输出最后那个大王的编号. 链表解法 function king($n,$m){ $monky = range(1,$n); $i = 0; while(count($monky)>1){ $i+=1; $head = array_shift($mon

F - System Overload(约瑟夫环问题)

Description Recently you must have experienced that when too many people use the BBS simultaneously, the net becomes very, very slow.To put an end to this problem, the Sysop has developed a contingency scheme for times of peak load to cut off net acc

Josephus环的四种解法(约瑟夫环)

约瑟夫环 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3…n分别表示)围坐在一张圆桌周围.从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列;依此规律重复下去,直到圆桌周围的人全部出列.通常解决这类问题时我们把编号从0~n-1,最后结果+1即为原问题的解引用别人的一个图:直观说明问题 分析: 第一步:从1开始报数为3的时候就删除3号结点第二步:从4号结点开始报数,当为3的时候删除6号结点:第三步:从7号结点开始报数,当为3的时候

约瑟夫环问题--递推解法

利用数学推导,如果能得出一个通式,就可以利用递归.循环等手段解决.下面给出推导的过程: (1)第一个被删除的数为 (m - 1) % n. (2)假设第二轮的开始数字为k,那么这n - 1个数构成的约瑟夫环为k, k + 1, k + 2, k +3, .....,k - 3, k - 2.做一个简单的映射. k         ----->  0              k+1    ------> 1              k+2    ------> 2           

小朋友学数据结构(1):约瑟夫环的链表解法、数组解法和数学公式解法

约瑟夫环的链表解法.数组解法和数学公式解法 约瑟夫环(Josephus)问题是由古罗马的史学家约瑟夫(Josephus)提出的,他参加并记录了公元66-70年犹太人反抗罗马的起义.约瑟夫作为一个将军,设法守住了裘达伯特城达47天之久,在城市沦陷之后,他和40名死硬的将士在附近的一个洞穴中避难.在那里,这些叛乱者表决说"要投降毋宁死".于是,约瑟夫建议每个人轮流杀死他旁边的人,而这个顺序是由抽签决定的.约瑟夫有预谋地抓到了最后一签,并且,作为洞穴中的两个幸存者之一,他说服了他原先的牺牲品

【好记性不如烂笔头】约瑟夫环问题之形象解法(其实就是实实在在的模拟一下游戏过程)

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using System.Threading.Tasks; 6 7 namespace 约瑟夫环游戏 8 { 9 class Program 10 { 11 /* 12 * 约瑟夫环(约瑟夫问题)是一个数学的应用问题:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围. 13 * 从编号为k的