vlambda博客
学习文章列表

约瑟夫环的几个新思路(使用C++STL与线性数据结构)

题目描述

n  个人围成一圈,从第一个人开始报数,数到  m  的人出列,再由下一个人重新从  1  开始报数,数到  m  的人再出圈,依次类推,直到所有的人都出圈,请输出依次出圈人的编号。

输入格式

输入两个整数n,m

输出格式

输出一行  n  个整数,按顺序输出每个出圈人的编号。

输入输出样例

输入 #1复制

10 3

输出 #1复制

3 6 9 2 7 1 8 5 10 4

由于这题数据范围非常小,因此可以用很多比较奇怪的算法。不过,命题者的初衷是希望我们使用链表进行模拟。

在这里,我使用了一个结构体 Peo 存储一个双向链表:

struct Peo{ int ID; //编号 Peo *next, *front;};

其中 ID 代表这个人的编号,输出时使用,另外两个指针分别指向上一个和下一个人,不过我们先要对其初始化。使用两个变量 totoutNum 来分别存储总人数和出局的数,然后让链表之间互相链接,最后首尾相连。

 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; }

  完整使用链表的代码如下!

#include<iostream>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>.

 #include<iostream>#include<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;}

这样的代码看起来就极度舒适。

不说了,继续刷题去了