考试的时候想了 Tarjan 和 Topsort ,发觉不对,改写玄学贪心:算 S 出发可以穿梭到达的点,以及原图上可以互相到达的点。枚举两个边界上相邻位置的点(比如 (x, 1) 和 (x, m) ),如果能被 S 穿梭到达,且两者可以直接到达(用并查集维护 Orz ),就是可行方案。不过显然有反例,因为两者之间也可以穿梭到达,不过不能与 S 到他们的路线重合……
这样想就非常恶心。
直接搜索四周,记录下到达相对位置 (x, y) 的实际坐标(可以是一个负数或者巨大的数)。如果能到达某个相同的相对做标的,是两个不同的实际坐标,那么是有可行方案的。
题不难,写一发题解是因为这题算上考试时做的时间,我总共做了三个小时 OrzOrz 。
#include <cstdio>
#include <algorithm>
#include <queue>
#include <ctype.h>
using namespace std;
const int INF = 1e9;
struct node {
int x, y;
node(int x = 0, int y = 0)
: x(x), y(y) { }
};
queue<node> Q;
int N, M;
char G[1550][1550];
int nxt[4][2] = {0,1,0,-1,1,0,-1,0};
int mk_x[1550][1550], mk_y[1550][1550];
int mm(int v, int m)
{
int t = (v % m + m) % m;
return t ? t : m;
}
bool bfs(node bg)
{
for (int i = 1; i <= N; ++i)
for (int j = 1; j <= M; ++j)
mk_x[i][j] = mk_y[i][j] = INF;
mk_x[bg.x][bg.y] = bg.x, mk_y[bg.x][bg.y] = bg.y;
while (!Q.empty()) Q.pop();
Q.push(bg);
while (!Q.empty()) {
node p = Q.front();
Q.pop();
for (int i = 0; i < 4; ++i) {
int tx = p.x + nxt[i][0], ty = p.y + nxt[i][1];
int gx = mm(tx, N), gy = mm(ty, M);
if (G[gx][gy] == '#' || mk_x[gx][gy] == tx && mk_y[gx][gy] == ty) continue;
if (mk_x[gx][gy] == INF && mk_x[gx][gy] == INF) {
Q.push(node(tx, ty));
mk_x[gx][gy] = tx, mk_y[gx][gy] = ty;
} else {
return true;
}
}
}
return false;
}
int main()
{
while (scanf("%d%d", &N, &M) == 2) {
node bg;
for (int i = 1; i <= N; ++i) {
char tt;
while ((tt = getchar()) != '#' && tt != '.' && tt != 'S');
G[i][1] = tt;
if (G[i][1] == 'S') bg = node(i, 1);
for (int j = 2; j <= M; ++j) {
G[i][j] = getchar();
if (G[i][j] == 'S') bg = node(i, j);
}
}
if (bfs(bg))
printf("Yes
");
else
printf("No
");
}
return 0;
}