📅  最后修改于: 2023-12-03 14:58:34.735000             🧑  作者: Mango
该题为高中信息学竞赛中的一道经典题目,题目内容如下:
在一个 $n \times m$ 的矩阵中,每个格子上面有一扇门,门的编号为 $1 \sim nm$。同时,每个门口都有一张门票,初始时所有门票都是 $0$。现在有 $k$ 个人按照如下方式进行操作:
现在给定 $n, m, k$ 三个参数,以及一个 $k \times 4$ 的矩阵,矩阵的每一行代表一个人的走法,第 $i$ 行的四个数字分别表示第 $i$ 个人的出发门口编号,走的方向(顺时针或逆时针,$0$ 表示顺时针,$1$ 表示逆时针),从第一个门口到第二个门口需要走过多少个门(不包括第一个门口和最后一个门口),以及是否初始持有一张门票($0$ 表示没有,$1$ 表示有,无票的门都为 $0$)。
你的任务是计算每扇门的最终票数。
对于每次操作,我们需要将门的票数和人的状态进行更新,因此我们需要设计门和人的两个类,同时需要记录每个人离开矩阵的时间。具体而言,我们可以使用如下的算法来解决此问题:
#include <iostream>
#include <vector>
using namespace std;
class Door {
public:
int id;
int count;
Door() : id(0), count(0) {};
Door(int id) : id(id), count(0) {};
};
class Person {
public:
int id;
int origin;
bool dir;
int steps;
bool ticket;
int arrival_time;
Person() : id(0), origin(0), dir(false), steps(0), ticket(false), arrival_time(0) {};
Person(int id, int origin, bool dir, int steps, bool ticket) : id(id), origin(origin), dir(dir), steps(steps), ticket(ticket), arrival_time(0) {};
};
int main() {
int n, m, k;
cin >> n >> m >> k;
vector<vector<Door>> doors(n, vector<Door>(m));
vector<Person> persons(k);
for (int i = 0; i < k; ++i) {
int origin, dir, steps, ticket;
cin >> origin >> dir >> steps >> ticket;
persons[i] = Person(i, origin - 1, dir == 1, steps, ticket == 1);
}
// 排序,按照出发门口编号
sort(persons.begin(), persons.end(), [](const Person& lhs, const Person& rhs) {
return lhs.origin < rhs.origin;
});
vector<vector<bool>> visited(k, vector<bool>(n * m, false));
for (int i = 0; i < k; ++i) {
auto& person = persons[i];
int cur_door = person.origin;
int dir = person.dir ? -1 : 1;
int steps = person.steps;
while (steps--) {
// 进门时更新状态
if (doors[cur_door / m][cur_door % m].count == 0) {
doors[cur_door / m][cur_door % m].id = cur_door + 1;
doors[cur_door / m][cur_door % m].count = person.ticket ? 1 : 0;
} else {
doors[cur_door / m][cur_door % m].count += person.ticket ? 1 : 0;
person.ticket |= 1;
}
visited[person.id][cur_door] = true;
cur_door = (cur_door + dir + n * m) % (n * m);
}
person.arrival_time = cur_door;
}
vector<int> ticket_count(n * m + 1, 0);
for (int i = 0; i < k; ++i) {
auto& person = persons[i];
if (!visited[person.id][person.arrival_time])
doors[person.arrival_time / m][person.arrival_time % m].count += person.ticket ? 1 : 0;
}
for (int i = 0; i < n; ++i) {
for (int j = 0; j < m; ++j) {
cout << doors[i][j].count << ' ';
}
cout << endl;
}
return 0;
}
该代码片段使用 vector 和 sort 实现,时间复杂度为 $O(k m n \log k)$,空间复杂度为 $O(k m n)$。如果使用 set 替换 vector,则时间复杂度可减少至 $O(k m n \log n)$,空间复杂度为 $O(k m)$。