约瑟夫环问题的第推公式是怎么来的阿~~

递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)
是怎么推来的呢??
请仔细说下
谢拉~~

/*约瑟夫问题的数学方法

无论是用链表实现还是用数组实现都有一个共同点:要模拟整个游戏过程,不仅程序写起来比较烦,而且时间复杂度高达O(nm),当n,m非常大(例如上百万,上千万)的时候,几乎是没有办法在短时间内出结果的。我们注意到原问题仅仅是要求出最后的胜利者的序号,而不是要读者模拟整个过程。因此如果要追求效率,就要打破常规,实施一点数学策略。

为了讨论方便,先把问题稍微改变一下,并不影响原意:

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。

我们知道第一个人(编号一定是m%n-1) 出列之后,剩下的n-1个人组成了一个新的约瑟夫环(以编号为k=m%n的人开始):
k k+1 k+2 ... n-2, n-1, 0, 1, 2, ... k-2
并且从k开始报0。

现在我们把他们的编号做一下转换:
k --> 0
k+1 --> 1
k+2 --> 2
...
...
k-2 --> n-2
k-1 --> n-1

变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k)%n

如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写递推公式:

令f[i]表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]

递推公式
f[1]=0;
f[i]=(f[i-1]+m)%i; (i>1)

有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1

由于是逐级递推,不需要保存每个f[i],程序也是异常简单:*/

#include <stdio.h>
main()
{
int n, m, i, s=0;
printf("N="); scanf("%d", &n);
printf("M="); scanf("%d", &m);
for(i=2; i<=n; i++) s=(s+m)%i;
printf("The winner is %d\n", s+1);
}

/*这个算法的时间复杂度为O(n),相对于模拟算法已经有了很大的提高。算n,m等于一百万,一千万的情况不是问题了。可见,适当地运用数学策略,不仅可以让编程变得简单,而且往往会成倍地提高算法执行效率。*/
温馨提示:内容为网友见解,仅供参考
无其他回答

约瑟夫环公式是怎样推导出来的?
1、约瑟夫环公式推导:已知n个人(以编号1,2,3...n分别表示)围坐在一张圆桌周围。从编号为k的人开始报数,数到m的那个人出列;他的下一个人又从1开始报数,数到m的那个人又出列。依此规律重复下去,直到圆桌周围的人全部出列。这个就是约瑟夫环问题的实际场景,有一种是要通过输入n,m,k三...

约瑟夫环问题的第推公式是怎么来的阿~~
f[i]=(f[i-1]+m)%i; (i>1)有了这个公式,我们要做的就是从1-n顺序算出f[i]的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1 由于是逐级递推,不需要保存每个f[i],程序也是异常简单:*\/ include <stdio.h> main(){ int n, m, i, s=0;printf("N=...

这或许是你能找到的最详细约瑟夫环数学推导!
解决约瑟夫环问题,可以采用倒推方式,即从最终状态反推原始状态。具体思路是,如果知道最后剩下的数字在最终序列中的位置,那么可以计算出它在原始序列中的位置。假设最后剩下的数字下标为x,那么在原始序列中它的位置可以通过特定公式计算得出。大部分解法到这里就结束了,但缺乏数学证明过程。现在我们详细...

有n个人围成一圈,顺序排号。凡报到3的人退出圈子,问最后留下的是原来...
以此有递推公式f(1)=0,f(i)=(f(i-1)+3)%i f(i)为第i次退出圈子的人 我们用for循环从2个人时开始反推,经过n-1次迭代,去除退出圈子的人,从而可以得到n个人时最后一个退出的人的标号为几,也就是最后留下的人的标号是几,因为我们每次标号都是从0开始所以最后退出的人的实际编号=标号+1....

约瑟夫环的问题求解
对于m=3的情况,问题变得复杂,没有直接的计算公式。但可以通过递推公式进行计算,或者使用简单的算法。这种算法同样可以扩展到m>3的其他情况。对于类似于“n个数排成一圈,从1开始每隔两个划去一个,求最后两个数之和”的问题,虽然不能直接套用公式,但在给出特定情况(如2000个数)时,可以通过...

敢死队问题 C\/C++
那么有了这个递推公式,是否可以求出J的形式化表示?目前看来,除了m=2的情况,答案是否定的。Knuth给出了m=2的形式化描述:设 n = 2^i + l 则 J(n,2) = 2l+1。 这个公式的证明比较巧妙,考虑到如果n=2^i, 则1会永远保持1号位,也就是最后的x=1。那么对于n = 2^i + l 的...

java编程17人编号为0-16围成一圈,0号人开始从1报数,凡是报数为3倍数的...
0,1,2,3,4...(n-3),(n-2)【(n-1)个人】 这个时候 ,这里重新构成了一个约瑟夫环。也就是说,这是一个递推的关系。这里我们进行了重新编号。那么 (n-1)个人和 n个人之间的编号不一样的。但是两者之间有一定的关系,可以冲新编号推导出老的 公式如下: i' = (i+k)%(n-1) ...

C语言编程:有n个人围成一圈,按顺序从1到n编号。从第一个人开始,报到3...
{ int i,j=0,k=0,n;int a[30]={0};printf("请输入有几个人玩游戏:");scanf("%d",&n);for(i=0;i<n;i++){ a=1;\/\/1代表活着,0代表出局 } for(i=1;i<4;i=i%3+1)\/\/控制i的值在[0,3]{ if(3==i&&a[j]!=0){ a[j]=0;printf("%d号玩家出局\\n",j+1);k...

JOSEPHUS 好人 求算法思路,最好有代码
递推公式 f[1]=0; f=(f+m) mod i; (i>1) 有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1 由于是逐级递推,不需要保存每个f,程序也是异常简单: c++ #include <stdio.h> int main() { int n, m, i, s...

约瑟夫环问题的算法设计是什么样子的??
这个就是约瑟夫环问题的实际场景,有一种是要通过输入n,m,k三个正整数,来求出列的序列。这个问题采用的是典型的循环链表的数据结构,就是将一个链表的尾元素指针指向队首元素。 p->link=head 解决问题的核心步骤:(程序的基本算法)1.建立一个具有n个链结点,无头结点的循环链表;2.确定第1个...

相似回答