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;
class List {
private:
//结点类型
struct node {
int data;
node* next;
node(int x, node* n = nullptr) :data(x), next(n) {};
};
int len;
node* head;//头结点
public:
List(int m = 0);
~List();
int Josephus(int m); //约瑟夫游戏函数,每一次返回下个人结点地址
};
List::List(int m)
{
len = m;
if (m == 0) head = nullptr;
else {
head = new node(1);
node* p = head, * q = nullptr;
for (int i = 2; i <= m; i++)
{
q = new node(i);
p->next = q;
p = q;
}
p->next = head; //初始化循环链表
}
}
int List::Josephus(int m)
{
if (len == 1) return head->data;
int k = 0;
node* p = head, * q;
for (int i = 0; i < m - 1; i++)
{
cin >> k;
if (k == 1) k = len + 1;
for (int i = 0; i < (k - 2)%len; i++)
{
p = p->next;
}
q = p->next;
p->next = q->next;
len--;
p = p->next;
}
head = p;
return p->data;
}
List::~List()
{
if (head)
{
delete head;
head = nullptr;
}
}
int main()
{
int m = 0;
cin >> m;
List mylist(m);
int n = mylist.Josephus(m);
cout << n << endl;
return 0;
}
方案二:数组模拟
#include<iostream> #define MAX 15000 using namespace std; int main() { int m = 0; cin >> m; int len = m; int arr[MAX]; int now = 0; for (int i = 0; i < m; i++) { arr[i] = i; } int k = 0; for (int i = 0; i < m - 1; i++) { cin >> k; int cnt = 1; while (cnt <= (k-1)%len) { now = (now + 1) % m; while(arr[now]==-1) now = (now + 1) % m; cnt++; } arr[now] = -1; len--; now = (now + 1) % m; while (arr[now]==-1) now = (now + 1) % m; } now = (now + 1) % m; while (arr[now]==-1) now = (now + 1) % m; cout << arr[now]+1 << endl; return 0; }
方案三:队列
#include<iostream> #include<queue> using namespace std; int main() { queue<int> q; int m = 0, k; cin >> m; for (int i = 1; i <= m; i++) { q.push(i); //入队 } for (int i = 0; i < m-1; i++) { cin >> k; for (int j = 0; j < (k - 1)%len; j++) { q.push(q.front()); q.pop(); } q.pop(); } cout << q.front() << endl; return 0; }