题目描述:
http://acm.hdu.edu.cn/showproblem.php?pid=1175
思路:
两枚欲消棋子的位置由用户输入,我们以其中一枚棋子的位置作为深搜起点,搜索路径即为连线。
从当前位置任选一个方向,走一步,若选择的方向与之前的方向一致,则没有转向,否则,转向次数加一。
而新位置有 4 种可能:
1.没有棋子
2.没有棋子,但已经被走过
3.有棋子,且为目标棋子
4.有棋子,但不是目标棋子
只需要处理情况 1 和情况 3,其余两种情况不用考虑。
代码:
#include<bits/stdc++.h>
using namespace std;
int n,m;
int maps[1000][1000];//棋盘信息
int y1,x1,y2,x2;//y行,x列
int dir[4][2] = {{0,-1}, {0,1}, {-1,0}, {1,0}};
bool have_result;
//row,col:当前访问位置
//pre_dir:之前连线的走向,用来判断是否转向
//turn_num:转向次数
void dfs(int row, int col,int pre_dir, int turn_num){
//转折次数超过两次 或 已经判断出两个棋子可以消除了
if(turn_num > 2 || have_result){
return;
}
//两个棋子可以消除
if(col == x2 && row == y2){
have_result = true;
return;
}
//任选一个方向,走一步 ,新位置有 4 种可能:
//没有棋子
//没有棋子,但已经被走过
//有棋子,且为目标棋子
//有棋子,但不是目标棋子
for(int i=0;i<4;i++){
int nx = col + dir[i][0];
int ny = row + dir[i][1];
if(nx>=0 && nx<m && ny>=0 && ny<n){
int new_num = turn_num;
//判断走到新位置时,是否进行了转向
if(pre_dir != -1 && i != pre_dir){
new_num++;
}
//新位置有棋子,且为目标棋子
if(ny == y2 && nx == x2){
dfs(ny, nx, i, new_num);
}
else if(maps[ny][nx] == 0){//新位置没有棋子
maps[ny][nx] = -1;
dfs(ny, nx, i, new_num);
maps[ny][nx] = 0;
}
//另外两种情况不做处理
}
}
}
int main(){
while(scanf("%d %d", &n, &m) && (n||m)){
for(int i=0;i<n;i++){
for(int j=0;j<m;j++){
scanf("%d", &maps[i][j]);
}
}
int k;
scanf("%d", &k);
for(int i=0;i<k;i++){
scanf("%d %d %d %d", &y1, &x1, &y2, &x2);
//记得减 1
y1--;x1--;y2--;x2--;
have_result = false;
//俩位置上有棋子,且棋子类型一致
if(maps[y1][x1] && maps[y2][x2] && maps[y1][x1] == maps[y2][x2]){
dfs(y1, x1, -1, 0);
}
if(have_result){
printf("YES
");
}
else{
printf("NO
");
}
}
}
}
//一组测试用例:
//3 4
//5 0 1 0
//5 0 0 0
//1 4 0 5
//4
//3 4 1 1
//1 1 3 4
//2 1 3 4
//3 4 2 1
//0 0
//
//NO
//NO
//YES
//YES