Time Limit: 20000/10000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 10223 Accepted Submission(s): 2690
Total Submission(s): 10223 Accepted Submission(s): 2690
Problem Description
“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
Input
输入数据有多组。每组数据的第一行有两个正整数n,m(0<n<=1000,0<m<1000),分别表示棋盘的行数与列数。在接下来的n行中,每行有m个非负整数描述棋盘的方格分布。0表示这个位置没有棋子,正整数表示棋子的类型。接下来的一行是一个正整数q(0<q<50),表示下面有q次询问。在接下来的q行里,每行有四个正整数x1,y1,x2,y2,表示询问第x1行y1列的棋子与第x2行y2列的棋子能不能消去。n=0,m=0时,输入结束。
注意:询问之间无先后关系,都是针对当前状态的!
注意:询问之间无先后关系,都是针对当前状态的!
Output
每一组输入数据对应一行输出。如果能消去则输出"YES",不能则输出"NO"。
Sample Input
3 4 1 2 3 4 0 0 0 0 4 3 2 1 4 1 1 3 4 1 1 2 4 1 1 3 3 2 1 2 4 3 4 0 1 4 3 0 2 4 1 0 0 0 0 2 1 1 2 4 1 3 2 3 0 0
Sample Output
YES NO NO NO NO YES
题意: 连连看。 就是给你一个N*M 的棋盘。 然后, 有Q次询问, 问两个坐标是否能消去(坐标可以相同)。 规则: 连线只能在棋盘内, 转折 turn <= 2;
思路:深搜。
先别考虑时间, 怎么判断是否转折了。
每次移动都有四个选择, 上, 下, 左, 右, 如图, 我是约定 0 代表 左 1 代表 右, 2 代表 上, 3 代表 下
那么 如果棋子是走 1(右), 3(下), 0(左), 那么就会到达 黄格。
转折了2次, 分别是 在 从 走1 变为 走3 的时候, 和 从 走3 变为 走0 的时候 发生了转折。
如果棋子是走 1 (右), 3( 下), 3(下), 1(右), 1(右) ,那么就会到达 灰格子。
也是发生了两次转折。 分别是从 走1 变为 走3 的时候,和 从 走3 变为 走1 的时候。 而 两次走3 和 两次走1 都未发生转折。
从上面的走法来看,不难发现, 只要当前走的方向与上次走的方向不一样就是 转折了。
那么 左 == (0, -1) 右 == (0, 1) 上 == (-1, 0) 下 == (1, 0);
下面就考虑时间问题啦!
剪枝: 首先 按照规则剪枝 坐标对应的值是0 或者 两坐标对应的值不相等 或者 两坐标相同的 或者 转折大于2的 就输出 (“no")。
然后是最关键的剪枝: 如果 turn == 2 但是 当前位置与 目标位置不在同一直线上就要退出。 因为至少需要一个转折才能让当前位置移动到与目标在同一直线。
if(turn == 2 && x != index_i && y != index_j) return;
如果 当前位置与目标位置在同一直线,但当前移动方向不能移动到 目标位置的。
#include <stdio.h>
#include <string.h>
#define max_size 1005
int num[max_size][max_size], visited[max_size][max_size], index_i, index_j, flag, n, m;
int a[4][2] = {1, 0, -1, 0, 0, 1, 0, -1};
void dfs(int x, int y, int turn, int index) {
if(flag)
return;
//违背规则的
if(turn > 2)
return;
if(turn == 2) {
//不在同一直线
if(x != index_i && y != index_j)
return;
//在同一列,运动方向不是往目标移动
if(x != index_i)
if(x - index_i > 0 && index != 1 || x - index_i < 0 && index != 0)
return;
//在同一行,运动方向不是往目标移动
if(y != index_j)
if(y - index_j > 0 && index != 3 || y - index_j < 0 && index != 2)
return;
}
//满足条件的
if(turn <= 2 && x == index_i && y == index_j) {
flag = 1;
return;
}
for(int i = 0; i < 4; ++i) {
int nx = x + a[i][0], ny = y + a[i][1];
if(!visited[nx][ny] && (!num[nx][ny] || nx == index_i && ny == index_j)) {
if(i != index && index != -1)
turn++;
visited[nx][ny] = 1;
dfs(nx, ny, turn, i);
visited[nx][ny] = 0;
if(i != index && index != -1)
turn--;
}
}
}
int main() {
while(scanf("%d%d", &n, &m) && n || m) {
for(int i = 0; i <= n + 1; ++i)
for(int j = 0; j <= m + 1; ++j)
visited[i][j] = -1;
for(int i = 1; i <= n; ++i)
for(int j = 1; j <= m; ++j) {
scanf("%d", &num[i][j]);
visited[i][j] = 0;
}
int Q;
scanf("%d", &Q);
while(Q--) {
int start_i, start_j;
scanf("%d%d%d%d", &start_i, &start_j, &index_i, &index_j);
flag = 0;
if(start_i != index_i || start_j != index_j)
if(num[start_i][start_j] == num[index_i][index_j] && num[start_i][start_j] > 0) {
visited[start_i][start_j] = 1;
dfs(start_i, start_j, 0, -1);
visited[start_i][start_j] = 0;
}
if(flag)
printf("YES\n");
else
printf("NO\n");
}
}
}