这道题本身比较麻烦,有四个方向,我们需要找到对应方向的下一个点。
暴力解法:
对于任意一步,当前点p和当前方向d,
记录p的状态为被访问
查询p+d是否被访问过,是则继续查询p+2d,直到找到p+nd没有被访问过,p+nd就是解
这样算法,如果测试例子是EWEWEWEWEWEWEWEWEW这种形式,复杂度是O(N2),hidden的例子这么大肯定过不去
优化解法
我们要优化算法,只能从每一步找对应的边界开始。我的做法和官方分析有出入,我们注意到,每次走完一步停下来的位置,就是之前访问过的某个点的附近一点。如果我们把每次访问的点附近的点都存起来,并剔除掉已经被访问过的点,这些点就是任意方向运动后的可能的位置的集合。那么上下左右四个方向,每个方向的每一行(列)维护一个这个点的集合,每次到一个新的点就把附近的没访问过的点放进去,每次只需在某一行的这些点中找对应的点即可。若使用set,插入删除寻找点的复杂度为O(log(N))。事实上我们只需要维护数值方向和水平方向即可。
#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <string>
#include <set>
using namespace std;
inline long long trans(int r, int c) {
return r * 51000 + c;
}
void findDir(map<int, set<int>>& ver, map<int, set<int>>& hor, map<long long, short>& m, int r, int c, char d, int& ansR, int& ansC) {
if (d == 'E') {
for (auto i = hor[r].begin(); i != hor[r].end(); i++) {
if (*i > ansC) {
ansC = *i;
break;
}
}
ansR = r;
}
if (d == 'N') {
int before = 0;
for (auto i = ver[c].begin(); i != ver[c].end(); i++) {
if (before < ansR && (*(i) > ansR)) {
ansR = before;
break;
}
before = *i;
}
ansC = c;
}
if (d == 'S') {
for (auto i = ver[c].begin(); i != ver[c].end(); i++) {
if (*i > ansR) {
ansR = *i;
break;
}
}
ansC = c;
}
if (d == 'W') {
int before = 0;
for (auto i = hor[r].begin(); i != hor[r].end(); i++) {
if (before < ansC && (*(i) > ansC)) {
ansC = before;
break;
}
before = *i;
}
ansR = r;
}
if (m[trans(ansR - 1, ansC)] == 0) {
ver[ansC].insert(ansR - 1);
}
else {
ver[ansC].erase(ansR - 1);
}
if (m[trans(ansR + 1, ansC)] == 0) {
ver[ansC].insert(ansR + 1);
}
else {
ver[ansC].erase(ansR + 1);
}
if (m[trans(ansR, ansC - 1)] == 0) {
hor[ansR].insert(ansC - 1);
}
else {
hor[ansR].erase(ansC - 1);
}
if (m[trans(ansR, ansC + 1)] == 0) {
hor[ansR].insert(ansC + 1);
}
else {
hor[ansR].erase(ansC + 1);
}
hor[ansR].erase(ansC);
ver[ansC].erase(ansR);
// cout << ansR << " " << ansC << endl;
}
int main()
{
int numTest, row, column;
cin >> numTest;
for (int l = 0; l < numTest; l++) {
map<int, set<int>> neighborVer;
map<int, set<int>> neighborHor;
map<long long, short> m;
string opS;
int numOp;
int r, c;
int sr, sc;
cin >> numOp >> r >> c >> sr >> sc;
cin >> opS;
m[trans(sr, sc)] = 1;
neighborHor[sr].insert(sc - 1);
neighborHor[sr].insert(sc + 1);
neighborVer[sc].insert(sr - 1);
neighborVer[sc].insert(sr + 1);
for (int i = 0; i < numOp; i++) {
char d = opS[i];
int ansR = sr, ansC = sc;
findDir(neighborVer, neighborHor, m, sr, sc, d, ansR, ansC);
sr = ansR;
sc = ansC;
m[trans(sr, sc)] = 1;
}
cout << "Case #" << l + 1 << ": " << sr << " " << sc << endl;
}
return 0;
}