目录
这道题看着就脑壳痛
一.题目
二.题解
先分析一下这道题目:
当人在推箱子的时候,如果直接往人站的方向推,就直接判断前方是否是墙或出界;
但当人需要换个方向推箱子时,就需要判断人是否能到箱子的另一面,这就是本题的难点。
下面就来解决难点:
很明显,箱子堵住了人去到箱子另一面的一条路,人要通过另一条路过去,就是说人现在的位置和将要到达的位置要在一个点双连通分量内,对,没错,就是点双连通分量。
好,来缕一下思路:
1.Tarjan处理处点双连通分量
2.预处理判断人是否能到箱子的四个方向
3.BFS搜索箱子能到的位置
4.输出答案
注意细节有太多!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
我是用O2优化过的
三.Code
#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#include <stack>
#include <queue>
using namespace std;
#define M 1505
int n, m, q, a[M][M], sx, sy, tx, ty, dfn[M * M], low[M * M], cnt, cut;
char g;
int dir[4][2] = {{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
bool vis[M][M], flag[M][M][5];
vector <int> G[M * M];
stack <int> s;
int id (int x, int y){
return m * (x - 1) + y;
}
struct node {
int xx, yy, d;
node (){};
node (int X, int Y, int D){
xx = X;
yy = Y;
d = D;
}
};
void Tarjan (int x, int y, int nx, int ny){//特别容易打错
int v = id (x, y);
dfn[v] = low[v] = ++ cnt;
for (int i = 0; i < 4; i ++){
int tox = x + dir[i][0];
int toy = y + dir[i][1];
if (a[tox][toy] || (tox == nx && toy == ny))
continue;
int u = id (tox, toy);
if (! dfn[u]){
s.push (u);
Tarjan (tox, toy, x, y);
low[v] = min (low[u], low[v]);
if (dfn[v] <= low[u]){
cut ++;
int k = 0;
while (k != u){
k = s.top ();
s.pop ();
G[k].push_back (cut);
}
G[u].push_back (cut);
G[v].push_back (cut);
}
}
else if (tox != nx || toy != ny)
low[v] = min (dfn[u], low[v]);
}
}
void prepare (){
queue <node> Q;
Q.push (node (sx, sy, 0));
vis[sx][sy] = 1;
while (! Q.empty ()){
node f = Q.front ();
Q.pop ();
for (int i = 0; i < 4; i ++){
int tox = f.xx + dir[i][0];
int toy = f.yy + dir[i][1];
if (a[tox][toy] || (tox == tx && toy == ty) || vis[tox][toy])
continue;
Q.push (node (tox, toy, 0));
vis[tox][toy] = 1;
}
}
}
bool check (int x, int y){
for (int i = 0; i < G[x].size (); i ++){
for (int j = 0; j < G[y].size (); j ++){
if (G[x][i] == G[y][j])
return 1;
}
}
return 0;
}
void BFS (){
queue <node> Q;
for (int i = 0; i < 4; i ++){
if (vis[tx - dir[i][0]][ty - dir[i][1]]){//一定要减,人在箱子前进方向的反面
Q.push (node (tx, ty, i));
flag[tx][ty][i] = 1;
}
}
while (! Q.empty ()){
node f = Q.front ();
Q.pop ();
int tox = f.xx + dir[f.d][0];
int toy = f.yy + dir[f.d][1];
if (! a[tox][toy]){
Q.push (node (tox, toy, f.d));
flag[tox][toy][f.d] = 1;
}
for (int i = 0; i < 4; i ++){
tox = f.xx - dir[i][0];
toy = f.yy - dir[i][1];
if (a[tox][toy] || flag[f.xx][f.yy][i] || i == f.d)
continue;
int u = id (f.xx - dir[f.d][0], f.yy - dir[f.d][1]), v = id (tox, toy);
if (check (u, v)){
Q.push (node (f.xx, f.yy, i));
flag[f.xx][f.yy][i] = 1;
}
}
}
}
int main (){
scanf ("%d %d %d", &n, &m, &q);
for (int i = 1; i <= n; i ++){
scanf ("\n");
for (int j = 1; j <= m; j ++){
scanf ("%c", &g);
if (g == '.')
a[i][j] = 0;
if (g == '#')
a[i][j] = 1;
if (g == 'A')
sx = i, sy = j, a[i][j] = 0;
if (g == 'B')
tx = i, ty = j, a[i][j] = 0;
}
}
for (int i = 0; i <= n + 1; i ++)
a[i][0] = a[i][m + 1] = 1;
for (int i = 0; i <= m + 1; i ++)
a[0][i] = a[n + 1][i] = 1;
for (int i = 1; i <= n; i ++){
for (int j = 1; j <= m; j ++){
if (! dfn[id (i, j)] && ! a[i][j])
Tarjan (i, j, 0, 0);
}
}
prepare ();
BFS ();
while (q --){
int x, y;
scanf ("%d %d", &x, &y);
if (flag[x][y][0] || flag[x][y][1] || flag[x][y][2] || flag[x][y][3] || (x == tx && y == ty))
printf ("YES\n");
else
printf ("NO\n");
}
return 0;
}