這道題本身比較麻煩,有四個方向,我們需要找到對應方向的下一個點。
暴力解法:
對於任意一步,當前點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;
}