约瑟夫环的几个新思路(使用C++STL与线性数据结构)
题目描述
输入格式
输入两个整数n,m
输出格式
输出一行
输入输出样例
输入 #1复制
10 3
输出 #1复制
3 6 9 2 7 1 8 5 10 4
由于这题数据范围非常小,因此可以用很多比较奇怪的算法。不过,命题者的初衷是希望我们使用链表进行模拟。
在这里,我使用了一个结构体 Peo
存储一个双向链表:
struct Peo{
int ID; //编号
Peo *next, *front;
};
其中 ID
代表这个人的编号,输出时使用,另外两个指针分别指向上一个和下一个人,不过我们先要对其初始化。使用两个变量 tot
, outNum
来分别存储总人数和出局的数,然后让链表之间互相链接,最后首尾相连。
for (int i = 1; i < tot - 1; i++) { n[i].front = n + i - 1; n[i].next = n + i + 1; n[i].ID = i + 1; }
n[0].front = n + tot - 1; n[0].next = n + 1; n[tot - 1].front = n + tot - 2; n[tot - 1].next = n;
n[0].ID = 1; n[tot - 1].ID = tot;
链表初始化完成之后,我们可以使用一个结构体指针 now
来表示我们现在模拟到哪一个人了。
Peo *now = n; //指向目前报数的人的指针
最后,我们需要用一种方法来删除链表当中的某一项,可以这样考虑,如果当前需要删除的项是 now
, 那么链表中需要修改的变量只有它前一项和后一项的两个指针,在代码实现上,将 now->front
的 next
更改为now->next
,然后 now->next
的 front
更改为now->front
就可以了。我们使用一个函数封装这一过程。
void _Cut(Peo *num)
{
num = num->front;
num->next = num->next->next;
num = num->next;
num->front = num->front->front;
}
完整使用链表的代码如下!
using namespace std;
struct Peo
{
int ID; //编号
Peo *next, *front;
Peo(){ next = front = nullptr; }
}n[100];
void _Cut(Peo *num)
{
num = num->front;
num->next = num->next->next;
num = num->next;
num->front = num->front->front;
}
int main()
{
int tot, outNum, nowNum = 1;
Peo *now = n; //指向目前报数的人的指针
cin >> tot >> outNum; //数据读入
for (int i = 1; i < tot - 1; i++) { n[i].front = n + i - 1; n[i].next = n + i + 1; n[i].ID = i + 1; }
n[0].front = n + tot - 1; n[0].next = n + 1; n[tot - 1].front = n + tot - 2; n[tot - 1].next = n;
n[0].ID = 1; n[tot - 1].ID = tot;
//初始化链表
while (tot > 0) {
if (nowNum == outNum) {
cout << now->ID << " "; //输出出局的人的编号
_Cut(now); //出局
nowNum = 1; //初始化数字
tot--; //总人数-1
now = now->next; //下一个人
}
else {
nowNum++; //数字+1
now = now->next; //下一个人
}
}
return 0;
}
使用链表的解法无疑是很清晰的,但是代码量过大,而且使用指针,容易出错,不方便调试。于是我就想,C++中有一个骚东西叫做STL,我能否使用STL来简化我的程序呢?
我们使用一个队列 q
进行模拟,在读取总人数和出局数字后,把这些人一个个地压入队列尾部。在使用队列之前,需要先加上头文件 <queue>
.
using namespace std;
int main()
{
int tot, outNum, nowNum = 1;
queue<int> q;
cin >> tot >> outNum; //读取数据
for (int i = 1; i <= tot; i++)q.push(i); //初始化队列
while (!q.empty()) //在队列不为空时继续模拟
{
if (nowNum == outNum)
{
cout << q.front() << " "; //打印出局的人的编号
q.pop(); //出局
nowNum = 1; //初始化现在的数字
}
else
{
nowNum++;
q.push(q.front()); //排至队尾
q.pop();
}
}
cout << endl;
return 0;
}
这样的代码看起来就极度舒适。
不说了,继续刷题去了