约瑟夫问题

来源:互联网 发布:淘宝店铺出租风险 编辑:程序博客网 时间:2024/06/05 14:12

约瑟夫问题:设有n个人围成一圈,每个人的编号依次为1,2,...,n。现从编号为k的人开始报数,数到m的人便出列,接着从出列的下一个人重新开始报数,数到m的人又出列,以此类推,直到所有人都出列为止。现要求该n个人的出列顺序,设为函数f(n,m,i)

算法分析:第一种情况,假设有10人,数到3出列。开始给这10个人编号:0,1,2,3,4,5,6,7,8,9。

第一次:编号为2 的人出列:0  1  3  4  5  6  7  8  9,出列的人为(m-1)%10=f(10,3,1);

出列后变为10-1=9人的约瑟夫问题,从编号3开始数:

3  4  5  6  7  8 9 0  1 (1

0  1  2  3  4  5  6  7  8(2)

可以发现((2)+3)%10=(1);序列f(10,3,2)=f(9,3,1)+3;

第二次:编号为5 的人出列:3  4   6  7  8 9 0  1 (1,出列的人为f(10,3,2)=f(9,3,1)+3;

相对于之前的9人约瑟夫问题来说序列变为:

3  4  6  7  8  90  1 (3)

0  1  3  4  5  6  7  8 (4)

出列后变为8人的约瑟夫问题,从编号6开始数:

6  7  8  9  0  1  3  4 (5

3  4  5  6  7  8 0  1 (6)

0  1  2  3  4  5  6  7 (7)

可以发现((7)+3)%9=(6);((6)+3)%10=(5);序列f(10,3,3)={[f(8,3,1)+3]%9+3}%10={f(9,3,2)+3}%10

依次类推,f(n,m,i)函数求第i次输出的人的编号;

f(n,m,i)=(m-1)%n;(n=1),

f(n,m,i)=[f(n-1,m,i-1)+m]%n;(n!=1),

具体的代码实现,如下:

当依次输出出列人的编号:

#include <stdio.h>#include <stdlib.h>int fun(int m,int k,int i){if(i==1)return (m+k-1)%m;elsereturn (fun(m-1,k,i-1)+k)%m;}int main(int argc, char* argv[]){for(int i=1;i<=10;i++)printf("第%2d次出环:%2d\n",i,fun(10,3,i));return 0;}
当输出留到最后的人的编号:

#include <stdio.h>#include <stdlib.h>int fun(int m,int k,int i){if(i==1)return (m+k-1)%m;elsereturn (fun(m-1,k,i-1)+k)%m;}int main(int argc, char* argv[]){//for(int i=1;i<=10;i++)printf("最后出列的是:%2d\n",fun(10,3,10));return 0;}


0 0
原创粉丝点击