题目描述
在一个 4×44×4 的棋盘上摆放了 1414 颗棋子,其中有 77 颗白色棋子,77 颗黑色棋子,有两个空白地带,任何一颗黑白棋子都可以向上下左右四个方向移动到相邻的空格,这叫行棋一步,黑白双方交替走棋,任意一方可以先走,如果某个时刻使得任意一种颜色的棋子形成四个一线(包括斜线),这样的状态为目标棋局。
输入格式
从文件中读入一个 4×44×4 的初始棋局,黑棋子用 B
表示,白棋子用 W
表示,空格地带用 O
表示。
输出格式
用最少的步数移动到目标棋局的步数。
输入输出样例
输入 #1
BWBO WBWB BWBW WBWO
输出 #1
5
Code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
public class 四子连棋 {
static class InputReader {
BufferedReader br;
public InputReader(InputStream stream) {
br = new BufferedReader(new InputStreamReader(stream));
}
public int nextInt() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
boolean negative = false;
if (c == '-') {
negative = true;
c = br.read();
}
int x = 0;
while (c > 32) {
x = x * 10 + c - '0';
c = br.read();
}
return negative ? -x : x;
}
public long nextLong() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
boolean negative = false;
if (c == '-') {
negative = true;
c = br.read();
}
long x = 0;
while (c > 32) {
x = x * 10 + c - '0';
c = br.read();
}
return negative ? -x : x;
}
public String next() throws IOException {
int c = br.read();
while (c <= 32) {
c = br.read();
}
StringBuilder sb = new StringBuilder();
while (c > 32) {
sb.append((char) c);
c = br.read();
}
return sb.toString();
}
public double nextDouble() throws IOException {
return Double.parseDouble(next());
}
}
static final int n = 4;
static char[][] g = new char[n][n];
static boolean flag = false;
// 方向数组
static int[][] next = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
// 检查横竖对角线和反对角线四条线有没有满足四子一色
static boolean check() {
for(int i = 0; i < n; i++) {
// 横代表当前行的每列上的元素相等
if(g[i][0] == g[i][1] && g[i][0] == g[i][2] && g[i][0] == g[i][3]) return true;
// 竖代表当前列的每行上的元素相等
if(g[0][i] == g[1][i] && g[0][i] == g[2][i] && g[0][i] == g[3][i]) return true;
}
// 正对角线
if(g[0][3] == g[1][2] && g[0][3] == g[2][1] && g[0][3] == g[3][0]) return true;
// 反对角线
if(g[0][0] == g[1][1] && g[0][0] == g[2][2] && g[0][0] == g[3][3]) return true;
return false;
}
static void dfs(int x1, int y1, int x2, int y2, char last, int u, int depth) {
if(u == depth) {
// 满足题意则添加标记
if(check()) flag = true;
return;
}
for(int i = 0; i < 4; i++) {
// 两个空白坐标下一步到达的坐标
int nx1 = x1 + next[i][0], ny1 = y1 + next[i][1];
int nx2 = x2 + next[i][0], ny2 = y2 + next[i][1];
// 下一步不能跃出棋盘 && 不能和上一步走的颜色重色
if(nx1 >= 0 && nx1 < n && ny1 >= 0 && ny1 < n && g[nx1][ny1] != last) {
// 交换位置
char tmp = g[nx1][ny1];
g[x1][y1] = tmp;
g[nx1][ny1] = 'O';
// 在该搜索方案下向下一层继续搜索
dfs(nx1, ny1, x2, y2, tmp, u + 1, depth);
// 还原现场
g[x1][y1] = 'O';
g[nx1][ny1] = tmp;
}
if(nx2 >= 0 && nx2 < n && ny2 >= 0 && ny2 < n && g[nx2][ny2] != last) {
char tmp = g[nx2][ny2];
g[x2][y2] = tmp;
g[nx2][ny2] = 'O';
dfs(x1, y1, nx2, ny2, tmp, u + 1, depth);
g[x2][y2] = 'O';
g[nx2][ny2] = tmp;
}
}
}
public static void main(String[] args) throws Exception{
InputReader in = new InputReader(System.in);
for(int i = 0; i < n; i++) g[i] = in.next().toCharArray();
int x1 = -1, y1 = -1, x2 = -1, y2 = -1; // 两个空白点坐标
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++) {
if(g[i][j] == 'O') {
if(x1 == -1) {
x1 = i; y1 = j; // 第一次找到空白,记录下第一个坐标点
} else {
x2 = i; y2 = j; // 第二次找到空白
}
}
}
int depth = 0; // 从第0层开始(一个节点还未开始走一步)
while(true) {
// 白棋走完黑棋走,谁先谁后没规定
dfs(x1, y1, x2, y2, 'W', 0, depth);
dfs(x1, y1, x2, y2, 'B', 0, depth);
// 如果当前层数满足可以找到目标期盼则退出下一层的递归
if(flag) break;
depth++; // 在下一层走
}
System.out.println(depth);
}
}