题目描述
连连看
“连连看”相信很多人都玩过。没玩过也没关系,下面我给大家介绍一下游戏规则:在一个棋盘中,放了很多的棋子。如果某两个相同的棋子,可以通过一条线连起来(这条线不能经过其它棋子),而且线的转折次数不超过两次,那么这两个棋子就可以在棋盘上消去。不好意思,由于我以前没有玩过连连看,咨询了同学的意见,连线不能从外面绕过去的,但事实上这是错的。现在已经酿成大祸,就只能将错就错了,连线不能从外围绕过。
玩家鼠标先后点击两块棋子,试图将他们消去,然后游戏的后台判断这两个方格能不能消去。现在你的任务就是写这个后台程序。
输入:
输入数据有多组。每组数据的第一行有两个正整数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;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。