洛谷P2346四子连珠游戏最短步数BFS解法详解

一、题目解读
洛谷P2346是一道经典的棋盘游戏问题,要求在一4x4黑白棋棋盘上,通过移动棋子使同色棋子形成四子一线(横、竖或对角线),计算达成目标所需的最少步数。题目考察BFS算法应用和状态空间搜索能力。
二、解题思路
状态表示:使用字符串存储棋盘状态,记录步数和当前执棋方
胜利判定:检查所有行、列和对角线是否存在四子一线
状态转移:对每个空格检查四周可移动的同色棋子
三、解题步骤
初始化队列,同时考虑黑白双方先手
每次取出队首状态检查是否达成目标
生成所有可能的下一个状态(移动有效棋子)
使用哈希表记录已访问状态避免重复计算
返回最先找到的解步数
四、完整代码
#include <iostream>
#include <queue>
#include <unordered_map>
#include <string>
#include <algorithm>
using namespace std;
// 定义棋盘状态结构体
struct State {
string board; // 棋盘状态字符串
int steps; // 到达该状态的步数
bool isBlack; // 当前该谁走棋
};
// 检查是否达到目标状态(四个一线)
bool isGoal(const string& board) {
// 检查所有行
for (int i = 0; i < 4; ++i) {
if (board[i*4] != 'O' && board[i*4] == board[i*4+1] &&
board[i*4] == board[i*4+2] && board[i*4] == board[i*4+3])
return true;
}
// 检查所有列
for (int i = 0; i < 4; ++i) {
if (board[i] != 'O' && board[i] == board[i+4] &&
board[i] == board[i+8] && board[i] == board[i+12])
return true;
}
// 检查对角线
if (board[0] != 'O' && board[0] == board[5] &&
board[0] == board[10] && board[0] == board[15])
return true;
if (board[3] != 'O' && board[3] == board[6] &&
board[3] == board[9] && board[3] == board[12])
return true;
return false;
}
// 获取所有可能的下一步状态
vector<State> getNextStates(const State& current) {
vector<State> nextStates;
const string& board = current.board;
char currentPlayer = current.isBlack ? 'B' : 'W';
// 找到所有空格位置
vector<int> emptyPos;
for (int i = 0; i < 16; ++i) {
if (board[i] == 'O') emptyPos.push_back(i);
}
// 对于每个空格,检查四周可以移动过来的棋子
for (int pos : emptyPos) {
int row = pos / 4;
int col = pos % 4;
// 检查四个方向
int dirs[4][2] = {{-1,0}, {1,0}, {0,-1}, {0,1}};
for (auto& dir : dirs) {
int newRow = row + dir[0];
int newCol = col + dir[1];
if (newRow >= 0 && newRow < 4 && newCol >= 0 && newCol < 4) {
int newPos = newRow * 4 + newCol;
if (board[newPos] == currentPlayer) {
// 可以移动这个棋子到空格
string newBoard = board;
swap(newBoard[newPos], newBoard[pos]);
nextStates.push_back({newBoard, current.steps + 1, !current.isBlack});
}
}
}
}
return nextStates;
}
int bfs(const string& initialBoard) {
queue<State> q;
unordered_map<string, bool> visited;
// 初始状态,黑方先走
q.push({initialBoard, 0, true});
// 白方先走的初始状态
q.push({initialBoard, 0, false});
visited[initialBoard + "1"] = true; // 黑方先走的标记
visited[initialBoard + "0"] = true; // 白方先走的标记
while (!q.empty()) {
State current = q.front();
q.pop();
if (isGoal(current.board)) {
return current.steps;
}
vector<State> nextStates = getNextStates(current);
for (const State& next : nextStates) {
string key = next.board + (next.isBlack ? "1" : "0");
if (!visited.count(key)) {
visited[key] = true;
q.push(next);
}
}
}
return -1; // 无解情况
}
int main() {
string board;
string line;
// 读取4x4棋盘
for (int i = 0; i < 4; ++i) {
cin >> line;
board += line;
}
int result = bfs(board);
cout << result << endl;
return 0;
}五、总结
本解法通过BFS高效搜索状态空间,利用字符串表示棋盘状态,结合哈希去重,确保在最短步数内找到解。算法时间复杂度取决于有效状态数,空间复杂度通过哈希优化。
原创内容 转载请注明出处





