约瑟夫问题之唐僧娶女汉子的故事

本文通过一个生动的故事背景引入约瑟夫环问题,并详细解释了其数学模型和递归解决方案,最后给出了C语言实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题:约瑟夫玩过一个杀人的游戏,我多么期望第一个被杀的是我,想半天,我也许想明白了,我也许没想明白。约瑟夫第一个就杀我吧,求你了。
下面是引用的约瑟夫问题
据说著名犹太历史学家 Josephus有过以下的故事:在罗马人占领乔塔帕特后,39 个犹太人与Josephus及他的朋友躲到一个洞中,39个犹太人决定宁愿死也不要被敌人抓到,于是决定了一个自杀方式,41个人排成一个圆圈,由第1个人开始报数,每报数到第3人该人就必须自杀,然后再由下一个重新报数,直到所有人都自杀身亡为止。然而Josephus 和他的朋友并不想遵从。首先从一个人开始,越过k-2个人(因为第一个人已经被越过),并杀掉第k个人。接着,再越过k-1个人,并杀掉第k个人。这个过程沿着圆圈一直进行,直到最终只剩下一个人留下,这个人就可以继续活着。问题是,给定了和,一开始要站在什么地方才能避免被处决?Josephus要他的朋友先假装遵从,他将朋友与自己安排在第16个与第31个位置,于是逃过了这场死亡游戏。

还有类似猴子当大王的故事等等,各种改编,我当然也可以改编成唐僧娶媳妇儿的故事,现在社会剩女太多,就等唐僧解决,可是唐僧只能解救一个,肿么办捏,于是唐僧想出了一招妙计,设定了个规则,最后一个剩下的女汉子就可以嫁给唐僧。请问我应该站哪个位置可以被唐僧娶走?好捉急啊,在线等!!!规则是这样的:女汉子总数为n,编号是(1,2,...n),站成个圈圈,规则是从第一个女汉子开始报数为m的人就被淘汰,m淘汰后,从m+1开始继续报数,最后一个剩下的女子才是剩女中的极品,就可以拜倒在唐僧的白龙马下了。

故事完了,下面就是数学模型了:

问题描述:n个人(编号0~(n-1)),从0开始报数,报到(m-1)的退出,剩下的人继续从0开始报数。求胜利者的编号。
我们知道第一个人(编号一定是(m-1) mod n) 出列之后,剩下的n-1个人组成了一个新的 约瑟夫环(以编号为k=m mod 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
变换后就完完全全成为了(n-1)个人报数的子问题,假如我们知道这个子问题的解:例如x是最终的胜利者,那么根据上面这个表把这个x变回去不刚好就是n个人情况的解吗?!!变回去的公式很简单,相信大家都可以推出来:x'=(x+k) mod n
如何知道(n-1)个人报数的问题的解?对,只要知道(n-2)个人的解就行了。(n-2)个人的解呢?当然是先求(n-3)的情况 ---- 这显然就是一个倒推问题!好了,思路出来了,下面写 递推公式
令f表示i个人玩游戏报m退出最后胜利者的编号,最后的结果自然是f[n]
递推公式
f[1]=0;
f=(f+m) mod i; (i>1)
有了这个公式,我们要做的就是从1-n顺序算出f的数值,最后结果是f[n]。因为实际生活中编号总是从1开始,我们输出f[n]+1

#include<stdio.h>
#include<stdlib.h>

int main()
{
int n,m,i,s=0;
printf("女汉子个数N 规则M = "); 
scanf("%d%d",&n,&m);
for(i=2; i<=n; i++)
{ 
         s=(s+m)%i;
 
}
printf("唐僧最终娶了%d号汉子\n",s+1);

system("pause");
return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值