约瑟夫问题:
——n个人围成一圈,第一个人从1开始报数,报m的将被杀掉,下一个人接着从1开始报。如此反复,最后剩下一个,求最后的胜利者。
解法:
——该内容略版,详解请参看大佬博客。
——递推公式:
Joseph(n,m)=(Joseph(n−1,m)+m)%n
f(n,m)表示:
n个人报数,每报到m时杀掉那个人,返回最终胜利者的编号。
f(n−1,m)表示:
n-1个人报数,每报到M时杀掉那个人,返回最终胜利者的编号。
——显而易见,上述是一个递归的过程,当有n个人时,是不能确定谁最终能存活,只有剩下一个时,才会知道谁最终活了下来。
——下面举例子模拟:11个人,报3的死亡。
下图为模拟过程,绿色为下标。
可只看黄色部分的左边(包括黄色部分),
黄色部分右边部分作用不是很大,方便理解过程。
——下面就从下向上看:盯住胜利者的下标变化。
—— 从图中可知最后胜利者为7,对应的下标为0。
- 只有1个人报数时,胜利者处于首位,下标为0。
即Joseph(1,3)=0; - 下面变成2个人报数,胜利者需在0号位向右移动3位,因为不能越界,最终胜利者位于1号位置。
即Joseph(2,3)=(Joseph(1,3)+3)%2; - 下面变成3个人报数,胜利者从1号位置向右移动3位,最终仍然处于1号位。
- …
- 下面变成11个人报数,胜利者处于6号位置。即从一开始这个位置上的人就注定不会死。
代码1:(递归)
#include<stdio.h>
int Joseph(int n,int m)
{
if(n==1)
return 0;
else
return (Joseph(n-1,m)+m)%n;
}
int main()
{
int n,m;
scanf("%d %d",&n,&m);
int p=Joseph(n,m);
printf("%d\n",p+1);
return 0;
}
代码2:(非递归)
#include<stdio.h>
int main()
{
int n,m,i,p=0;
scanf("%d %d",&n,&m);
for(i=2;i<=n;i++)
p=(p+m)%i;
printf("%d\n",p+1);
return 0;
}