题目描述
围棋棋盘由纵横各19条线垂直相交组成,棋盘上一共19x19=361个交点。对弈双方一方执白棋,一方执黑棋,落子时只能将棋子置于交点上。
“气”是围棋中很重要的一个概念,某个棋子有几口气,是指其上下左右方向四个相邻的交叉点中,有几个交叉点没有棋子。在棋盘的边缘上的棋子最多有3口气,在棋盘角点的棋子最多有2口气,其它情况最多有4口气。
所有同色棋子的气之和叫作该色棋子的气。需要注意的是,同色棋子重合的气点,对于该颜色棋子来说,只能计算一次气。
输入描述
输入包括两行数据,每行数据以空格分隔,数据个数是2的整数倍,每两个数是一组,代表棋子在棋盘上的坐标。坐标的原点在棋盘左上角点,第一个值是行号,范围从0到18;第二个值是列号,范围从0到18。第一行表示黑棋的坐标,第二行表示白棋的坐标。
输出描述
输出两个数字,以空格分隔,第一个数代表黑棋的气数,第二个数代表白棋的气数。
示例
输入:
0 5 8 9 9 10
5 0 9 9 9 8
输出:
8 7
解题思路
- 初始化棋盘: 创建一个19x19的棋盘,用于记录黑棋和白棋的位置。
- 记录棋子位置: 根据输入,将黑棋和白棋的位置记录在棋盘上。
- 计算气数: 对于每个棋子,检查其上下左右四个方向的相邻点,如果该点为空且未被计算过,则计入气数。
- 输出结果: 输出黑棋和白棋的总气数。
代码实现
Java
import java.util.*;
public class Solution {
private static final int SIZE = 19;
private static final int[][] DIRECTIONS = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String[] blackInput = scanner.nextLine().split(" ");
String[] whiteInput = scanner.nextLine().split(" ");
Set<String> blackStones = new HashSet<>();
Set<String> whiteStones = new HashSet<>();
for (int i = 0; i < blackInput.length; i += 2) {
int x = Integer.parseInt(blackInput[i]);
int y = Integer.parseInt(blackInput[i + 1]);
blackStones.add(x + "," + y);
}
for (int i = 0; i < whiteInput.length; i += 2) {
int x = Integer.parseInt(whiteInput[i]);
int y = Integer.parseInt(whiteInput[i + 1]);
whiteStones.add(x + "," + y);
}
int blackLiberties = calculateLiberties(blackStones, whiteStones);
int whiteLiberties = calculateLiberties(whiteStones, blackStones);
System.out.println(blackLiberties + " " + whiteLiberties);
}
private static int calculateLiberties(Set<String> stones, Set<String> opponentStones) {
Set<String> liberties = new HashSet<>();
for (String stone : stones) {
String[] parts = stone.split(",");
int x = Integer.parseInt(parts[0]);
int y = Integer.parseInt(parts[1]);
for (int[] dir : DIRECTIONS) {
int nx = x + dir[0];
int ny = y + dir[1];
if (nx >= 0 && nx < SIZE && ny >= 0 && ny < SIZE) {
String pos = nx + "," + ny;
if (!stones.contains(pos) && !opponentStones.contains(pos)) {
liberties.add(pos);
}
}
}
}
return liberties.size();
}
}
Python
SIZE = 19
DIRECTIONS = [(-1, 0), (1, 0), (0, -1), (0, 1)]
def calculate_liberties(stones, opponent_stones):
liberties = set()
for stone in stones:
x, y = map(int, stone.split(','))
for dx, dy in DIRECTIONS:
nx, ny = x + dx, y + dy
if 0 <= nx < SIZE and 0 <= ny < SIZE:
pos = f"{nx},{ny}"
if pos not in stones and pos not in opponent_stones:
liberties.add(pos)
return len(liberties)
black_input = input().split()
white_input = input().split()
black_stones = set()
white_stones = set()
for i in range(0, len(black_input), 2):
x, y = int(black_input[i]), int(black_input[i + 1])
black_stones.add(f"{x},{y}")
for i in range(0, len(white_input), 2):
x, y = int(white_input[i]), int(white_input[i + 1])
white_stones.add(f"{x},{y}")
black_liberties = calculate_liberties(black_stones, white_stones)
white_liberties = calculate_liberties(white_stones, black_stones)
print(black_liberties, white_liberties)
C++
#include <iostream>
#include <vector>
#include <set>
#include <sstream>
using namespace std;
const int SIZE = 19;
const int DIRECTIONS[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
int calculateLiberties(const set<string>& stones, const set<string>& opponentStones) {
set<string> liberties;
for (const auto& stone : stones) {
int x, y;
char comma;
istringstream iss(stone);
iss >> x >> comma >> y;
for (const auto& dir : DIRECTIONS) {
int nx = x + dir[0];
int ny = y + dir[1];
if (nx >= 0 && nx < SIZE && ny >= 0 && ny < SIZE) {
string pos = to_string(nx) + "," + to_string(ny);
if (stones.find(pos) == stones.end() && opponentStones.find(pos) == opponentStones.end()) {
liberties.insert(pos);
}
}
}
}
return liberties.size();
}
int main() {
string blackInput, whiteInput;
getline(cin, blackInput);
getline(cin, whiteInput);
set<string> blackStones, whiteStones;
istringstream blackIss(blackInput), whiteIss(whiteInput);
int x, y;
while (blackIss >> x >> y) {
blackStones.insert(to_string(x) + "," + to_string(y));
}
while (whiteIss >> x >> y) {
whiteStones.insert(to_string(x) + "," + to_string(y));
}
int blackLiberties = calculateLiberties(blackStones, whiteStones);
int whiteLiberties = calculateLiberties(whiteStones, blackStones);
cout << blackLiberties << " " << whiteLiberties << endl;
return 0;
}
JavaScript
const SIZE = 19;
const DIRECTIONS = [[-1, 0], [1, 0], [0, -1], [0, 1]];
function calculateLiberties(stones, opponentStones) {
const liberties = new Set();
stones.forEach(stone => {
const [x, y] = stone.split(',').map(Number);
DIRECTIONS.forEach(([dx, dy]) => {
const nx = x + dx;
const ny = y + dy;
if (nx >= 0 && nx < SIZE && ny >= 0 && ny < SIZE) {
const pos = `${nx},${ny}`;
if (!stones.has(pos) && !opponentStones.has(pos)) {
liberties.add(pos);
}
}
});
});
return liberties.size;
}
const blackInput = prompt("Enter black stones:").split(' ');
const whiteInput = prompt("Enter white stones:").split(' ');
const blackStones = new Set();
const whiteStones = new Set();
for (let i = 0; i < blackInput.length; i += 2) {
const x = parseInt(blackInput[i]);
const y = parseInt(blackInput[i + 1]);
blackStones.add(`${x},${y}`);
}
for (let i = 0; i < whiteInput.length; i += 2) {
const x = parseInt(whiteInput[i]);
const y = parseInt(whiteInput[i + 1]);
whiteStones.add(`${x},${y}`);
}
const blackLiberties = calculateLiberties(blackStones, whiteStones);
const whiteLiberties = calculateLiberties(whiteStones, blackStones);
console.log(blackLiberties, whiteLiberties);
复杂度分析
- 时间复杂度: O(n),其中 n 是棋子的数量。每个棋子的四个方向都需要检查。
- 空间复杂度: O(n),用于存储棋子和气的位置。
总结
通过记录棋子的位置并检查其相邻点,我们可以有效地计算黑棋和白棋的气数。不同语言的实现方式略有不同,但核心思路一致。