约瑟夫问题

约瑟夫问题:设有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  9 0  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;
	else
		return (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;
	else
		return (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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值