题目

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

题解

连连看游戏的后台实现

根据我们接触到的练练看游戏,可以确定一下规则:

  1. 要点击两个不同的位置

  2. 点击的两个位置应该是合法位置

  3. 点击的两个位置应该对应的是相应的棋子,并且不能有空白格

  4. 棋子间路径只能通过空白格,并且最多只能转过两个拐角

如同正常的BFS一样,只是每次拓展路径要拓展一条直线,记录下到该点转过的拐角,拓展3层(两个拐角)

判断目标点是否能到达即可

代码

/*
By:OhYee
Github:OhYee
Email:oyohyee@oyohyee.com
Blog:http://www.cnblogs.com/ohyee/

かしこいかわいい?
エリーチカ!
要写出来Хорошо的代码哦~
*/

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <string>
#include <iostream>
#include <vector>
#include <list>
#include <queue>
#include <stack>
using namespace std;

//DEBUG MODE
#define debug 0

//循环
#define REP(n) for(int o=0;o<n;o++)

const int maxn = 1005;

int m,n;
int Map[maxn][maxn];
int dis[maxn][maxn];

typedef pair<int,int> point;

int BFS(int s1,int s2,int v1,int v2) {
   define con1(nn) (nn<=0||nn>n) 
   define con2(mm) (mm<=0||mm>m)
    //位置错误
    if(con1(s1) || con1(v1) || con2(s2) || con2(v2))
        return -1;
    //同一位置
    if(s1 == v1 && s2 == v2)
        return -1;
    //棋子不同 或 无棋子
    if(Map[s1][s2] != Map[v1][v2] || Map[s1][s2]==0)
        return -1;

    queue<point> Q;
    memset(dis,-1,sizeof(dis));

    Q.push(point(s1,s2));
    dis[s1][s2] = 0;

    while(!Q.empty()) {
        int th1 = Q.front().first;
        int th2 = Q.front().second;
        Q.pop();

        //达到终点
        if(th1 == v1 && th2 == v2)
            break;

        //拓展节点
       define condition \
        (next1 > 0 && next1 <= n && next2 > 0 && next2 <= m \
        && (Map[next1][next2] == 0||(next1==v1 && next2==v2)))

       define push \
        if(dis[next1][next2]==-1 && dis[th1][th2]<=2) {\
            Q.push(point(next1,next2));\
            dis[next1][next2] = dis[th1][th2] + 1;\
        }\

        int next1,next2;
        for(next1 = th1,next2 = th2 + 1;condition;next2++) {
            push;
        }
        for(next1 = th1 + 1,next2 = th2;condition;next1++) {
            push;
        }
        for(next1 = th1,next2 = th2 - 1;condition;next2--) {
            push;
        }
        for(next1 = th1 - 1,next2 = th2;condition;next1--) {
            push;
        }

    }
    return dis[v1][v2];
}

bool Do() {
    if(scanf("%d%d",&n,&m),n == 0 && m == 0)
        return false;
    for(int i = 1;i <= n;i++)
        for(int j = 1;j <= m;j++)
            scanf("%d",&Map[i][j]);
    int T;
    scanf("%d",&T);
    while(T--) {
        int s1,s2,v1,v2;
        scanf("%d%d%d%d",&s1,&s2,&v1,&v2);
        printf("%s\n",BFS(s1,s2,v1,v2)==-1?"NO":"YES");
    }
    return true;
}

int main() {
    while(Do());
    return 0;
}