题目链接: 连连看
题目大意: 给一张n*m大小的图,问查询的两个点k1与k2之间能不能消掉,消掉的条件是通过走没有东西的路径拐弯不超过两次到达目标点。(0表示没有东西,>1的物品表示相应的东西),并且不能够走外围。
解题思路: 从起点向终点搜索可行解,有一个重要的剪枝是:当无转弯的次数时,还没到达与终点相同的行或列时排除该条搜索分枝。
AC代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
using namespace std;
int image[1010][1010],n,m;
int vis[1010][1010];
int x1,y1,x2,y2,flag;
int _next[4][2] = {0,1,1,0,0,-1,-1,0}; //方向: right down left up
inline bool judge (int x, int y) {
if(x < 1 || x > n || y < 1 || y > m) {
return false;
}
return true;
}
void DFS (int x, int y, int dis, int change_size) {
if(change_size > 2 || flag == 1) {
return ;
} //check1:可行与不可行
if(x == x2 && y == y2) {
flag = 1;
return ;
} //check2: 搜索树的叶
if(image[x][y] != 0 && dis != -1) {
return ;
} //check3:非出发点与终点不能有值
if(change_size == 2 && (x != x2 && y != y2)) {
return ;
} //check4: 无转弯次数并且还没到达与终点的相同行或列
int now_x,now_y;
for (int i = 0; i < 4; i++) {
now_x = x + _next[i][0];
now_y = y + _next[i][1];
if(judge(now_x, now_y) && vis[now_x][now_y] == 0) {
if(dis == -1 || i == dis) {
vis[now_x][now_y] = 1;
DFS(now_x, now_y, i, change_size);
vis[now_x][now_y] = 0;
}else {
vis[now_x][now_y] = 1;
DFS(now_x, now_y, i, change_size + 1);
vis[now_x][now_y] = 0;
}
if(flag == 1) return ;
}
}
return ;
}
int main() {
int T,i,j;
while(~scanf("%d%d", &n,&m) && (n || m)) {
for (i = 1; i <= n; i++) {
for (j = 1; j <= m; j++) {
scanf("%d", &image[i][j]);
}
}
//query:T
scanf("%d",&T);
while (T--) {
scanf("%d%d%d%d", &x1, &y1, &x2, &y2);
if(judge(x1,y1) && judge(x2,y2) && image[x1][y1] == image[x2][y2] && image[x1][y1] != 0) {
memset(vis,0,sizeof(vis));
vis[x1][y1] = 1;
flag = 0;
DFS(x1, y1, -1, 0);
if(flag == 1) {
puts("YES");
}else {
puts("NO");
}
}else {
puts("NO");
}
}
}
return 0;
}