1

题目描述

连连看
“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。

输入:
输入数据有多组。每组数据的第一行有两个正整数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时,输入结束。
注意:询问之间无先后关系,都是针对当前状态的!

输出:
每一组输入数据对应一行输出。如果能消去则输出"YES",不能则输出"NO"。

题目思路

连连看是一种益智游戏,规则如下:在一个棋盘上放置了许多棋子。如果两个相同的棋子可以通过一条线连接起来(线不能经过其他棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去135。

对于这个后台程序的任务是判断玩家点击的两个方块是否可以消去125。

输入数据有多组,每组数据的第一行有两个正整数n和m,分别表示棋盘的行数和列数235。接下来的n行描述了棋盘的方格分布,每行有m个非负整数,表示棋子的类型135。然后是一个正整数q,表示接下来有q次询问135。每个询问占一行,包含四个正整数x1、y1、x2、y2,表示询问第x1行y1列的棋子与第x2行y2列的棋子能否消去135。

输出每组输入数据对应一行输出135。如果能消去,则输出"YES",否则输出"NO"。

注意:询问之间没有先后关系,都是针对当前状态的235。

实现1

#include <iostream>
#include <vector>

using namespace std;

bool canEliminate(vector<vector<int>>& board, int x1, int y1, int x2, int y2) {
    // 判断两个方块是否相同
    if (board[x1][y1] != board[x2][y2]) {
        return false;
    }
    
    // 判断是否可以通过一条线连接
    // 水平方向连接
    int cnt = 0;
    if (x1 == x2) {
        int start = min(y1, y2) + 1;
        int end = max(y1, y2);
        for (int i = start; i < end; i++) {
            if (board[x1][i] != 0) {
                cnt++;
            }
        }
    }
    // 垂直方向连接
    else if (y1 == y2) {
        int start = min(x1, x2) + 1;
        int end = max(x1, x2);
        for (int i = start; i < end; i++) {
            if (board[i][y1] != 0) {
                cnt++;
            }
        }
    }
    // 需要转弯的连接
    else {
        // 水平方向转弯
        int cnt1 = 0;
        int start1 = min(y1, y2) + 1;
        int end1 = max(y1, y2);
        for (int i = start1; i < end1; i++) {
            if (board[x1][i] != 0) {
                cnt1++;
            }
        }
        
        // 垂直方向转弯
        int cnt2 = 0;
        int start2 = min(x1, x2) + 1;
        int end2 = max(x1, x2);
        for (int i = start2; i < end2; i++) {
            if (board[i][y2] != 0) {
                cnt2++;
            }
        }
        
        cnt = cnt1 + cnt2;
    }
    
    // 判断转弯次数是否超过两次
    if (cnt > 2) {
        return false;
    }
    
    return true;
}

int main() {
    int n, m;
    while (cin >> n >> m && (n != 0 || m != 0)) {
        vector<vector<int>> board(n, vector<int>(m));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> board[i][j];
            }
        }
        
        int q;
        cin >> q;
        while (q--) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            
            if (canEliminate(board, x1, y1, x2, y2)) {
                cout << "YES" << endl;
            } else {
                cout << "NO" << endl;
            }
        }
    }
    
    return 0;
}

实现2(BFS)

#include <iostream>
#include <vector>
#include <queue>

using namespace std;

bool canEliminate(vector<vector<int>>& board, int x1, int y1, int x2, int y2) {
    // 判断两个方块是否相同
    if (board[x1][y1] != board[x2][y2]) {
        return false;
    }
    
    int n = board.size();
    int m = board[0].size();
    
    // 定义四个方向的偏移量
    int dx[] = {-1, 1, 0, 0};
    int dy[] = {0, 0, -1, 1};
    
    // 使用BFS进行搜索
    vector<vector<vector<bool>>> visited(n, vector<vector<bool>>(m, vector<bool>(3, false)));
    queue<pair<pair<int, int>, pair<int, int>>> q;
    q.push(make_pair(make_pair(x1, y1), make_pair(0, 0)));
    visited[x1][y1][0] = true;
    
    while (!q.empty()) {
        pair<pair<int, int>, pair<int, int>> cur = q.front();
        q.pop();
        
        int x = cur.first.first;
        int y = cur.first.second;
        int turns = cur.second.first;
        int direction = cur.second.second;
        
        // 如果找到了第二个方块,则可以消去
        if (x == x2 && y == y2) {
            return true;
        }
        
        // 向四个方向扩展
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            
            // 判断是否在棋盘范围内且未被访问过
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny][turns]) {
                // 如果是直线方向
                if (i == direction) {
                    q.push(make_pair(make_pair(nx, ny), make_pair(turns, i)));
                    visited[nx][ny][turns] = true;
                }
                // 如果是转弯方向
                else {
                    // 如果转弯次数已经超过两次,则不再继续扩展
                    if (turns >= 2) {
                        continue;
                    }
                    
                    q.push(make_pair(make_pair(nx, ny), make_pair(turns + 1, i)));
                    visited[nx][ny][turns + 1] = true;
                }
            }
        }
    }
    
    return false;
}

int main() {
    int n, m;
    while (cin >> n >> m && (n != 0 || m != 0)) {
        vector<vector<int>> board(n, vector<int>(m));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> board[i][j];
            }
        }
        
        int q;
        cin >> q;
        while (q--) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            
            if (canEliminate(board, x1, y1, x2, y2)) {
                cout << "YES" << endl;
            } else {
                cout << "NO" << endl;
            }
        }
    }
    
    return 0;
}

实现3(DFS)

#include <iostream>
#include <vector>
#include <stack>

using namespace std;

bool canEliminate(vector<vector<int>>& board, int x1, int y1, int x2, int y2) {
    // 判断两个方块是否相同
    if (board[x1][y1] != board[x2][y2]) {
        return false;
    }
    
    int n = board.size();
    int m = board[0].size();
    
    // 定义四个方向的偏移量
    int dx[] = {-1, 1, 0, 0};
    int dy[] = {0, 0, -1, 1};
    
    // 使用栈进行搜索
    vector<vector<vector<bool>>> visited(n, vector<vector<bool>>(m, vector<bool>(3, false)));
    stack<pair<pair<int, int>, pair<int, int>>> st;
    st.push(make_pair(make_pair(x1, y1), make_pair(0, -1)));
    visited[x1][y1][0] = true;
    
    while (!st.empty()) {
        pair<pair<int, int>, pair<int, int>> cur = st.top();
        st.pop();
        
        // 如果找到了第二个方块,则可以消去
        if (cur.first.first == x2 && cur.first.second == y2) {
            return true;
        }
        
        int x = cur.first.first;
        int y = cur.first.second;
        int turns = cur.second.first;
        int direction = cur.second.second;
        
        // 向四个方向扩展
        for (int i = 0; i < 4; i++) {
            int nx = x + dx[i];
            int ny = y + dy[i];
            
            // 判断是否在棋盘范围内且未被访问过
            if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny][turns]) {
                // 如果是直线方向
                if (i == direction) {
                    st.push(make_pair(make_pair(nx, ny), make_pair(turns, i)));
                    visited[nx][ny][turns] = true;
                }
                // 如果是转弯方向
                else {
                    // 如果转弯次数已经超过两次,则不再继续扩展
                    if (turns >= 2) {
                        continue;
                    }
                    
                    st.push(make_pair(make_pair(nx, ny), make_pair(turns + 1, i)));
                    visited[nx][ny][turns + 1] = true;
                }
            }
        }
    }
    
    return false;
}

int main() {
    int n, m;
    while (cin >> n >> m && (n != 0 || m != 0)) {
        vector<vector<int>> board(n, vector<int>(m));
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                cin >> board[i][j];
            }
        }
        
        int q;
        cin >> q;
        while (q--) {
            int x1, y1, x2, y2;
            cin >> x1 >> y1 >> x2 >> y2;
            
            if (canEliminate(board, x1, y1, x2, y2)) {
                cout << "YES" << endl;
            } else {
                cout << "NO" << endl;
            }
        }
    }
    
    return 0;
}

刘福蓝
6 声望0 粉丝