约瑟夫环的几个新思路(使用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--; //总人数-1now = now->next; //下一个人}else {nowNum++; //数字+1now = 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;}
这样的代码看起来就极度舒适。
不说了,继续刷题去了
