原本以为是一道很简单的模拟题,结果写了一个小时。。。很长时间不碰算法题,的确手感差很多。不过我觉得随着刷题慢慢多起来应该会好的。
题目的意思也有点含糊,需要自己去猜,大概意思就是槽里有一堆木头,每个槽刚开始的时候只有一个,需要移过来移过去,有四种方式,这四种方式都是针对木头而言的,因此我们必须时刻记录每个木头的位置。当然还需要数据结构记录槽的状态,最后需要输出。
四种移动方式有一些是共通的,因此需要将其抽象成函数,我这里抽象了三个函数:
void ret_block(int x);
将木头x头顶的木头归还到原本的槽里面(i
号木头到i
号槽)
void mve(int x, int idx);
将木头x
移动到槽idx
的位置,之所以不叫move
是因为不想和标准库的move
函数冲突
void pile(int x, int idx);
将木头x
以及其头顶的所有木头移动到槽idx
虽然使用三个函数简化了四种操作,但是我觉得自己分离的不够清晰,按道理讲pile
函数应该调用mve
函数,因为一个是移动一个木头,一个是移动一堆木头,可是因为使用的是vector
,导致无法随机插入。
顺带吐槽一下:我为了控制不输出最后的换行专门写了一个Newline
函数类,但是直接报错。。有的OJ要求不能有,有的又要求必须有。。
看了一下别人的题解,有两点收获:
- 不用判断整个字符串再确定是什么命令,判断一下首字母就可以了
- 可以使用
erase
函数整块删除。自己就是因为不知道这个函数写的比较复杂,还是要对STL更加熟悉才行
再研究了一下书上的题解,发现果然pile
函数可以和move
函数合并,而且可是使用resize
函数进行删除。
对于这种多种指令的,我们要提取出指令之间的共同点,编写函数以减少重复代码。
#include <iostream>
#include <vector>
#include <string>
#include <array>
using namespace std;
namespace {
const string QUIT = "quit";
const string MOVE = "move";
const string ONTO = "onto";
const string OVER = "over";
const string PILE = "pile";
constexpr int MAXN = 25 + 5;
array<vector<int>, MAXN> blocks;
array<pair<int, int>, MAXN> pos;
int n;
}
void init() {
cin >> n;
for (int i = 0; i < n; ++i) {
blocks[i].push_back(i);
pos[i] = {i, 0};
}
}
void mve(int x, int idx) {
blocks[idx].push_back(x);
blocks[pos[x].first].pop_back();
pos[x].first = idx;
pos[x].second = blocks[idx].size() - 1;
}
void pile(int x, int idx) {
auto &block_x = blocks[pos[x].first];
auto &block_dst = blocks[idx];
int origin_pos = pos[x].second;
int y;
for (int i = origin_pos; i < block_x.size(); ++i) {
y = block_x[i];
block_dst.push_back(y);
pos[y].first = idx;
pos[y].second = block_dst.size() - 1;
}
for (int i = block_x.size() - 1; i >= origin_pos; --i) block_x.pop_back();
}
void ret_block(int x) {
//return blocks that are stacked on top of x
auto &block_x = blocks[pos[x].first];
int y;
for (int i = block_x.size() - 1; i > pos[x].second; --i) {
y = block_x.back();
mve(y, y);
}
}
void work() {
int x, y;
string action, prep;
while (cin >> action) {
if (action == QUIT) break;
cin >> x >> prep >> y;
if (pos[x].first == pos[y].first) continue;
if (action == MOVE) {
if (prep == ONTO) {
//move x onto y
ret_block(x);
ret_block(y);
mve(x, pos[y].first);
} else {
ret_block(x);
mve(x, pos[y].first);
}
} else {
if (prep == ONTO) {
ret_block(y);
pile(x, pos[y].first);
} else {
pile(x, pos[y].first);
}
}
}
}
class Newline {
bool first;
public:
Newline(bool _fisrt = true):first(_fisrt) {}
inline void operator ()();
};
inline void Newline::operator()() {
if (first) {
first = false;
} else {
cout << "\n";
}
}
void print() {
Newline newline;
for (int i = 0; i < n; ++i) {
//newline();
cout << i << ":";
for (auto x : blocks[i]) {
cout << " " << x;
}
cout << "\n";
}
}
int main() {
ios::sync_with_stdio(false);
init();
work();
print();
}