题目来源:中国大学MOOC - 北京大学《数据结构与算法》- 第二章 线性表编程作业
3、约瑟夫问题(10分)
题目内容:
有n只猴子,按顺时针方向围成一圈选大王(编号从1到n),从第1号开始报数,一直数到m,数到m的猴子退出圈外,剩下的猴子再接着从1开始报数。就这样,直到圈内只剩下一只猴子时,这个猴子就是猴王,编程求输入n,m后,输出最后猴王的编号。
输入格式:
输入包含两个整数,第一个是n,第二个是m (0 < m,n <=300)。
输出格式:
输出包含一行,即最后猴王的编号。
输入样例:18 2
输出样例:5
时间限制:500ms内存限制:32000kb
思路:因涉及节点的删除操作以及循环遍历数据的操作,我采用循环双链表进行数据存储和处理。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
using namespace std;
void solution();
//定义双循环链表节点
typedef struct Node
{
int number;
struct Node *next;
struct Node *prev;
Node()
{
number = 0;
prev = next = NULL;
}
Node(int n)
{
number = n;
prev = next = NULL;
}
} Node;
//定义猴子序列的双循环链表类
class MonkeyList
{
private:
Node *head;
Node *rear;
int len;
//将序号为num的元素从链表中删除,即被淘汰
bool remove(int num)
{
Node *p = head;
do
{
if (p->number == num)
{
p->prev->next = p->next;
p->next->prev = p->prev;
if (p == head)
{
head = p->next;
}
if (p == rear)
{
rear = p->prev;
}
delete p;
len--;
// cout << num << " has been deleted." << endl;
return true;
}
p = p->next;
} while (p != head);
return false;
}
public:
MonkeyList()
{
len = 0;
head = rear = NULL;
}
MonkeyList(int l)
{
len = l;
if (len == 0)
{
head = rear = NULL;
return;
}
head = new Node(1);
rear = head;
for (int i = 2; i <= len; i++)
{
Node *node = new Node(i);
node->next = head;
head->prev = node;
rear->next = node;
node->prev = rear;
rear = rear->next;
}
}
//依次报数,报到m的被删除
void countOff(int m)
{
Node *p = head;
int i = 1;
while (len > 1)
{
if (i == m)
{
Node *tmp = p->next;
remove(p->number);
p = tmp;
i = 1;
continue;
}
p = p->next;
i++;
}
cout << head->number << endl;
}
};
int main()
{
int T = 0;
int t = 0;
T = 1;
while (t < T)
{
solution();
t++;
}
system("pause");
return 0;
}
void solution()
{
int m, n;
cin >> n >> m;
MonkeyList *list = new MonkeyList(n);
list->countOff(m);
}