连连看 |
---|
题意: 给定一个n*m的连连看的图,有q次操作,问点击(sx,sy)与(ex,ey)能否使方格消失(!!但是,就算可以消失,也不能改变原图,这q次操作相互之间没有联系)。消失的条件详见题目。
题解: 一开始还以为是判断给定的连连看图能否全部消失,但是只是针对两个方格的询问,并且前后没有联系的话,那只要通过DFS就能做,无非多一个记录路线方向以及拐弯次数。针对这个拐弯次数,可以有一个剪枝,有无这个剪枝,是109MS和6770MS的差距,不过题目给的时间足够长,所以没有剪枝也能过。
#include<bits/stdc++.h>
using namespace std;
const int N = 1e3 + 10;
int flag;
int n, m, q;
int sx, sy;
int ex, ey;
int G[N][N];
int vis[N][N];
int dir[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
void dfs(int x, int y, int di, int cnt) { //坐标、路线防线、拐弯次数
if(cnt > 2 || flag) return; //超过限定的拐弯次数或者已经判断到可以消失了,退出
if(cnt == 2 && (x - ex) != 0 && (y - ey) != 0) return ; //剪枝:拐弯次数已达上限
//直接判断此时的坐标与目标坐标是否在同一直线,不在即可退出
if(x == ex && y == ey) {
flag = 1;
return ;
}
for(int i = 0; i < 4; i++) {
int nx = x + dir[i][0];
int ny = y + dir[i][1];
if(nx < 1 || nx > n || ny < 1 || ny > m || vis[nx][ny]) continue;
if(G[nx][ny] == 0 || nx == ex && ny == ey) {
vis[nx][ny] = 1;
if(di == -1 || di == i) dfs(nx, ny, i, cnt);
else dfs(nx, ny, i, cnt + 1);
vis[nx][ny] = 0; //回溯:很重要的一环,判断完某条路线之后记得恢复vis标记
}
}
return ;
}
int main() {
while(~scanf("%d%d", &n, &m) && (n + m)) {
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
scanf("%d", G[i] + j);
scanf("%d", &q);
while(q--) {
flag = 0;
memset(vis, 0, sizeof vis);
scanf("%d%d%d%d", &sx, &sy, &ex, &ey);
if(G[sx][sy] == G[ex][ey] && G[sx][sy]) dfs(sx, sy, -1, 0);
if(flag) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}