hdu 1175 连连看

来源:互联网 发布:阿里云服务器老是掉线 编辑:程序博客网 时间:2024/05/21 13:57
Time Limit: 20000/10000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
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 41 2 3 40 0 0 04 3 2 141 1 3 41 1 2 41 1 3 32 1 2 43 40 1 4 30 2 4 10 0 0 021 1 2 41 3 2 30 0
 

Sample Output
YESNONONONOYES
 

题意: 连连看。  就是给你一个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 1005int 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");        }    }}

原创粉丝点击