题目描述 Description
在一个4*4的棋盘上摆放了14颗棋子,其中有7颗白色棋子,7颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。
● | ○ | ● | |
○ | ● | ○ | ● |
● | ○ | ● | ○ |
○ | ● | ○ |
输入描述 Input Description
从文件中读入一个4*4的初始棋局,黑棋子用B表示,白棋子用W表示,空格地带用O表示。
输出描述 Output Description
用最少的步数移动到目标棋局的步数。
样例输入 Sample Input
BWBO
WBWB
BWBW
WBWO
样例输出 Sample Output
5
数据范围及提示 Data Size & Hint
hi
分析:
典型的广度搜索题目,我们通过构造棋盘,通过使用int类型的数字替换黑白以及空白棋,使用0,-1,1代表棋子的上下左右移动,简化棋子之间的移动判断,但是要注意这里有先手和后手之分。其实该题目也可以理解成移动两个空白子的位置使黑子或者白子成线。
代码如下:
public class BFSTest {
private static volatile boolean flag = false;
//DFS搜索的最大层数
private static volatile int maxLevel = -1;
//坐标移动
private static final int[] moveX = {-1,0,1,0};
private static final int[] moveY = {0,1,0,-1};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("请输入棋子:");
//构造棋盘
int[][] array = new int[4][4];
//空白的位置
int o_x1 = -1;
int o_y1 = -1;
int o_x2 = -1;
int o_y2 = -1;
//数据准备构造棋盘格 1 代表 黑 2 代表白 3代表空
for (int i = 0; i < 4; i++){
char[] tmp = scanner.nextLine().toCharArray();
for (int j = 0; j < 4; j++){
if (tmp[j] == 'B'){
array[i][j] = 1;
} else if (tmp[j] == 'W'){
array[i][j] = 2;
} else {
array[i][j] = 3;
if (-1 == o_x1){
o_x1 = i;
o_y1 = j;
} else {
o_x2 = i;
o_y2 = j;
}
}
}
}
scanner.close();
for (maxLevel = 0;; maxLevel++){
BFSSearch(array, o_x1, o_y1, o_x2, o_y2, 1, 1); //黑白先下
BFSSearch(array, o_x1, o_y1, o_x2, o_y2, 2, 1); //白先下
if (flag){
System.out.println(maxLevel);
return;
}
}
}
//成线判断
public static boolean judge(int[][] chars){
//对角线成线
if (chars[0][0] == chars[1][1] && chars[0][0] == chars[2][2] &&
chars[0][0] == chars[3][3]) return true;
if (chars[3][0] == chars[2][1] && chars[3][0] == chars[1][2] &&
chars[3][0] == chars[0][3]) return true;
//横线或竖线
for (int i = 0; i < 4; i++){
if (chars[i][0] == chars[i][1] && chars[i][0] == chars[i][2] &&
chars[i][0] == chars[i][3]) return true;
if (chars[0][i] == chars[1][i] && chars[0][i] == chars[2][i] &&
chars[0][i] == chars[3][i]) return true;
}
return false;
}
//可移动判断
public static boolean canMove(int[][] arr, int i, int j, int last){
//移动后的空格的坐标的颜色和操作人的颜色必须不同并且此次移动该空格还在棋盘内,否则不能进行 (例如持黑色棋子先移动则他应该移动白子)
if (i >= 0 && i <= 3 && j >= 0 && j <= 3 && arr[i][j] != last) return true;
return false;
}
public static void BFSSearch(int[][] arr, int x1, int y1, int x2, int y2, int first, int level){
if (judge(arr)){
flag = true;
return;
}
if (level > maxLevel) return;
for (int i = 0; i < 4; i++){
int nx = x1 + moveX[i];
int ny = y1 + moveY[i];
int nx2 = x2 + moveX[i];
int ny2 = y2 + moveY[i];
//移动第一格
if (canMove(arr, nx, ny, first)){
//空格和要替换的位置交换
int tmp = arr[nx][ny];
arr[nx][ny] = arr[x1][y1];
arr[x1][y1] = tmp;
BFSSearch(arr, nx, ny, x2, y2, arr[x1][y1], level+1);
//恢复之前的位置
tmp = arr[nx][ny];
arr[nx][ny] = arr[x1][y1];
arr[x1][y1] = tmp;
}
//移动第二格
if (canMove(arr, nx2, ny2, first)){
//交换位置
int tmp = arr[nx2][ny2];
arr[nx2][ny2] = arr[x2][y2];
arr[x2][y2] = tmp;
BFSSearch(arr, x1, y1, nx2, ny2, arr[x2][y2], level+1);
//恢复位置
tmp = arr[nx2][ny2];
arr[nx2][ny2] = arr[x2][y2];
arr[x2][y2] = tmp;
}
}
}
}