经典问题----约瑟夫问题(数学递推)
题目简介:百练OJ2746
有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这 个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。或正宗约瑟夫问题
思路简介:
约瑟夫问题是学链表结构时的老问题,一般用循环链表做,但由于链表解法复杂度为m*n,当m、n较大时,这种模拟运算较为浪费时间,但观察一下,可以发现其中有一些规律。
比如说m为3,n我们从2开始,如果要使某位被选中最后获胜,则其位置必定为1,即第2个人(按0、1、2数);而当n为3时,只有位置是第2个的人才会最后获胜。
举例:下图(盗的)绿框为当n为11,m为3时,各轮元素所在位置;黄框为各轮被淘汰的元素;红框为最后一个留下的元素。

据上表,可以这样理解,当最后一轮淘汰开始的时候各元素的位置相当于最后第二轮各元素的位置向前移动了m(即3格),而前面3格的元素除了已被淘汰的,剩下的补充的队伍后面。由此反过来可以理解:
递推公式:
f(N,M)=(f(N−1,M)+M)%N
f(N,M)表示,N个人报数,每报到M时杀掉那个人,最终胜利者的编号
f(N−1,M)表示,N-1个人报数,每报到M时杀掉那个人,最终胜利者的编号
后面取模是因为防止前者相加过大,超过n。
递推代码:
#include <iostream> #include <cmath> #include<stdio.h> #include <cstdio> #include <cstring> #include<algorithm> using namespace std; int main() { while (1) { int N;//人的总个数 int M;//间隔多少个人 cin >> N; cin >> M; int result = 0;//N=1情况 for (int i = 2; i <= N; i++) { result = (result + M) % i;//根据淘汰情况实时调整人数 } cout << "最后自杀的人或者猴子是:" << result + 1 << endl;//result要加1 } return 0; }
浙公网安备 33010602011771号