题目描述
author: 原OJ链接:https://acm.sjtu.edu.cn/OnlineJudge-old/problem/1038
Description
话说二哥当年学习数据结构的时候遇到了那道猴子报数的题目,其实这就是经典的约瑟夫问题。
可是当年的二哥还是个毛头小子,只会用模拟的方法,而其他同学却使用了一些令二哥完全摸不到头脑的方法。
……二哥一怒之下改了题目……
话说当年花果山的猴子要选大王,选举办法如下:
所有猴子按1-M编号围坐一圈,二哥站在圈中心,由二哥指定一个整数Kn,
之后猴子们从1号开始按顺序报数,报到Kn的猴子退出到圈外,二哥再报出一个整数Kn+1,
然后由刚刚退出的猴子的下一只猴子再开始报数,如此循环报数,直到圈内只剩下一只猴子时,这只猴子就是大王。
由于二哥希望通过此种方法控制花果山,所以现在二哥把他制定的整数序列告诉你,希望你帮他预先算出那只猴子会成为大王。
Input Format
第一行 一个整数M,表示一共有M只猴子
第二行到第M行,每行一个整数 表示二哥即将指定的M-1个整数。这些数都大于0。
Output Format
一个整数,表示最后剩下那只猴子的编号。
Hint
对于40%的数据,M<=1000, K<=1000
对于70%的数据,M<=10000, K<=10000
对于100%的数据,M<=10000, K<=100000000
Sample Input
5
1
2
3
4
Sample Output
4
时空磁盘限制(运行时)
时间限制: 1000 ms
内存空间限制: 256 MiB
磁盘空间限制: 无限制
解决方案
#include <iostream>
using namespace std;
int main()
{
int m;
cin >> m;
int ind = 0;
int *stk = new int[m-1];
for (int i=0;i<=m-2;++i) {
cin >> stk[i];
// ind = ((ind + m - k) % (i+1) + (i+1)) % (i+1);
}
for (int i=1;i<=m-1;++i) {
ind = (ind + stk[m-1-i]) % (i+1);
}
cout << ind+1;
return 0;
}
总结
本题用暴力解法,即构造一个循环链表,再模拟过程,肯定对,但是效率低。所以要找出地推关系。这里参考了link,由于本题的报数值会变化,故递推式稍有不同。
假设每次淘汰猴子时,都会重新按照接下来的报数顺序将所有猴子安排至一个数组中。设
f
(
M
,
N
)
f(M, N)
f(M,N)表示,当猴子数为
M
M
M,报数值为
N
N
N时,幸存者所在的下标。那么我们很自然地知道,当
M
=
1
M=1
M=1时,无论
N
N
N的值为多少,
f
(
M
,
N
)
=
0
f(M,N)=0
f(M,N)=0(此时只剩下下标为0的猴子不被淘汰)。那么如何推出
M
=
2
M=2
M=2时的幸存者下标值呢?我们考虑逆向推导,当猴子数为
M
M
M,报数值为
N
N
N时,把上一轮(猴子数为
M
+
1
M+1
M+1,报数值为
N
−
1
N-1
N−1)被淘汰的猴子插回列表中。那么列表中所有的猴子需要先加上
N
N
N,由于会溢出,需要再模
M
M
M。即
f
(
M
,
N
)
=
(
f
(
M
−
1
,
N
+
1
)
+
N
)
%
M
f(M,N) = (f(M-1,N+1)+N)\%M
f(M,N)=(f(M−1,N+1)+N)%M
根据这个递推关系用循环得到初始时,幸存者下标位于何处。注意实际编号比下标多1。
声明
题目来自校内OJ平台,本人没有题目的版权。如有侵权,请联系本人删除。