#C58. 【华为OD机考 统一考试机试C卷】围棋的气
【华为OD机考 统一考试机试C卷】围棋的气
题目链接
【华为OD机考 统一考试机试C卷】围棋的气(C++ Java JavaScript Python)
https://blog.csdn.net/banxia_frontend/article/details/134908319
题目描述
围棋棋盘由纵横各19条线垂直相交组成,棋盘上一共19 x 19 = 361 个交点,对弈双方一方执白棋,一方执黑棋,落子时只能将棋子置于交点上。
“气”是围棋中很重要的一个概念,某个棋子有几口气,是指其上下左右方向四个相邻的交叉点中,有几个交叉点没有棋子,由此可知:
- 在棋盘的边缘上的棋子最多有 3 口气(黑1),在棋盘角点的棋子最多有2口气(黑2),其他情况最多有4口气(白1)
- 所有同色棋子的气之和叫做该色棋子的气,需要注意的是,同色棋子重合的气点,对于该颜色棋子来说,只能计算一次气,比如下图中,黑棋一共4口气,而不是5口气,因为黑1和黑2中间红色三角标出来的气是两个黑棋共有的,对于黑棋整体来说只能算一个气。
- 本题目只计算气,对于眼也按气计算,如果您不清楚“眼”的概念,可忽略,按照前面描述的规则计算即可。
现在,请根据输入的黑棋和白棋得到坐标位置,计算黑棋和白棋一共各有多少气?
输入描述
输入包含两行数据,
每行数据以空格分隔,数据个数是2的整数倍,每两个数是一组,代表棋子在棋盘上的坐标; 坐标的原点在棋盘左上角点,第一个值是行号,范围从0到18;第二个值是列号,范围从0到18。
举例说明:如:
0 5 8 9 9 10 5 0 9 9 9 8
第一行数据表示三个坐标(0, 5)、(8, 9)、(9, 10) 第一行表示黑棋的坐标,第二行表示白棋的坐标。 题目保证输入两行数据,无空行且每行按前文要求是偶数个,每个坐标不会超出棋盘范围。
输出描述
两个数字以空格分隔,第一个数代表黑棋的气数,第二个数代表白棋的气数。
8 7
用例
输入
0 5 8 9 9 10
5 0 9 9 9 8
输出
8 7
说明
数数黑棋一共8口气,数数白棋一共7口气。
解法1
解题思路
在这个例子中,我们有两组棋子的坐标。第一组是黑棋的坐标,第二组是白棋的坐标。
首先,得到两个整数数组,分别代表黑棋和白棋的位置。
黑棋的坐标数组为:{0_5, 8_9, 9_10} 白棋的坐标数组为:{5_0, 9_9, 9_8}
然后,我们计算每组棋子的"气"。
对于黑棋,我们检查每个棋子周围的四个位置,得到的"气"的坐标集合为:{"0_4", "0_6", "1_5", "7_9", "8_8", "8_10", "9_9", "9_11", "10_10"}。然后,我们从这个集合中减去黑棋的位置和白棋占据的位置,得到最终的"气"的数量为8。
对于白棋,我们同样检查每个棋子周围的四个位置,得到的"气"的坐标集合为:{"4_0", "5_1", "6_0", "8_9", "9_8", "9_10", "10_9", "10_8"}。然后,我们从这个集合中减去白棋的位置和黑棋占据的位置,得到最终的"气"的数量为7。
所以,黑棋的"气"的数量为8,白棋的"气"的数量为7。
C++
#include <iostream>
#include <sstream>
#include <vector>
#include <unordered_set>
using namespace std;
// 最大的棋盘边界索引
const int maxSide = 18;
// 解析输入的坐标字符串,返回整数数组
vector<int> parseCoordinates(string input) {
stringstream ss(input);
int num;
vector<int> coordinates;
while (ss >> num) {
coordinates.push_back(num);
}
return coordinates;
}
// 计算棋子的气数
int counting(vector<int>& alias, vector<int>& enemy) {
// 创建一个新的unordered_set,用于存储棋子的气
unordered_set<string> count;
// 遍历己方棋子的坐标
for (int i = 0; i < alias.size(); i += 2) {
int x = alias[i];
int y = alias[i + 1];
string pos = to_string(x) + "_" + to_string(y);
// 将己方棋子的位置添加到集合中
count.insert(pos);
// 分别检查上下左右四个方向,如果存在气则添加到集合中
if (x > 0) {
count.insert(to_string(x - 1) + "_" + to_string(y));
}
if (x < maxSide) {
count.insert(to_string(x + 1) + "_" + to_string(y));
}
if (y > 0) {
count.insert(to_string(x) + "_" + to_string(y - 1));
}
if (y < maxSide) {
count.insert(to_string(x) + "_" + to_string(y + 1));
}
}
// 计算得到的气数减去己方棋子的数量
int res = count.size();
// 减去敌方棋子占据的气点
for (int i = 0; i < enemy.size(); i += 2) {
string pos = to_string(enemy[i]) + "_" + to_string(enemy[i + 1]);
if (count.find(pos) != count.end()) {
res--;
}
}
return res - alias.size() / 2;
}
int main() {
string line;
// 读取黑棋的坐标
getline(cin, line);
vector<int> locBlacks = parseCoordinates(line);
// 读取白棋的坐标
getline(cin, line);
vector<int> locWhites = parseCoordinates(line);
// 输出黑棋和白棋的气数,两个数字以空格分隔
cout << counting(locBlacks, locWhites) << " " << counting(locWhites, locBlacks) << endl;
return 0;
}
Java
import java.util.Scanner;
import java.util.Set;
import java.util.HashSet;
public class Main {
// 最大的棋盘边界索引
static int maxSide = 18;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 读取黑棋的坐标
int[] locBlacks = parseCoordinates(in.nextLine());
// 读取白棋的坐标
int[] locWhites = parseCoordinates(in.nextLine());
// 输出黑棋和白棋的气数,两个数字以空格分隔
System.out.println(counting(locBlacks, locWhites) + " " + counting(locWhites, locBlacks));
}
// 计算棋子的气数
static int counting(int[] alias, int[] enemy) {
// 创建一个新的HashSet,用于存储棋子的气
Set<String> count = new HashSet<>();
// 遍历己方棋子的坐标
for (int i = 0; i < alias.length; i += 2) {
int x = alias[i];
int y = alias[i + 1];
String pos = x + "_" + y;
// 将己方棋子的位置添加到集合中
count.add(pos);
// 分别检查上下左右四个方向,如果存在气则添加到集合中
if (x > 0) {
count.add((x - 1) + "_" + y);
}
if (x < maxSide) {
count.add((x + 1) + "_" + y);
}
if (y > 0) {
count.add(x + "_" + (y - 1));
}
if (y < maxSide) {
count.add(x + "_" + (y + 1));
}
}
// 计算得到的气数减去己方棋子的数量
int res = count.size();
// 减去敌方棋子占据的气点
for (int i = 0; i < enemy.length; i += 2) {
String pos = enemy[i] + "_" + enemy[i + 1];
if (count.contains(pos)) {
res--;
}
}
return res - alias.length / 2;
}
// 解析输入的坐标字符串,返回整数数组
static int[] parseCoordinates(String input) {
String[] tokens = input.split(" ");
int[] coordinates = new int[tokens.length];
for (int i = 0; i < tokens.length; i++) {
coordinates[i] = Integer.parseInt(tokens[i]);
}
return coordinates;
}
}
javaScript
const readline = require('readline');
// 创建readline接口
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
// 最大的棋盘边界索引
const maxSide = 18;
// 解析输入的坐标字符串,返回整数数组
function parseCoordinates(input) {
return input.split(' ').map(Number);
}
// 计算棋子的气数
function counting(alias, enemy) {
// 创建一个新的Set,用于存储棋子的气
let count = new Set();
// 遍历己方棋子的坐标
for (let i = 0; i < alias.length; i += 2) {
let x = alias[i];
let y = alias[i + 1];
let pos = x + "_" + y;
// 将己方棋子的位置添加到集合中
count.add(pos);
// 分别检查上下左右四个方向,如果存在气则添加到集合中
if (x > 0) {
count.add((x - 1) + "_" + y);
}
if (x < maxSide) {
count.add((x + 1) + "_" + y);
}
if (y > 0) {
count.add(x + "_" + (y - 1));
}
if (y < maxSide) {
count.add(x + "_" + (y + 1));
}
}
// 计算得到的气数减去己方棋子的数量
let res = count.size;
// 减去敌方棋子占据的气点
for (let i = 0; i < enemy.length; i += 2) {
let pos = enemy[i] + "_" + enemy[i + 1];
if (count.has(pos)) {
res--;
}
}
return res - alias.length / 2;
}
// 读取黑棋的坐标
rl.on('line', (blackInput) => {
let locBlacks = parseCoordinates(blackInput);
// 读取白棋的坐标
rl.on('line', (whiteInput) => {
let locWhites = parseCoordinates(whiteInput);
// 输出黑棋和白棋的气数,两个数字以空格分隔
console.log(counting(locBlacks, locWhites) + " " + counting(locWhites, locBlacks));
rl.close();
});
});
Python
# 最大的棋盘边界索引
maxSide = 18
# 解析输入的坐标字符串,返回整数数组
def parseCoordinates(input):
return list(map(int, input.split()))
# 计算棋子的气数
def counting(alias, enemy):
# 创建一个新的set,用于存储棋子的气
count = set()
# 遍历己方棋子的坐标
for i in range(0, len(alias), 2):
x = alias[i]
y = alias[i + 1]
pos = str(x) + "_" + str(y)
# 将己方棋子的位置添加到集合中
count.add(pos)
# 分别检查上下左右四个方向,如果存在气则添加到集合中
if x > 0:
count.add(str(x - 1) + "_" + str(y))
if x < maxSide:
count.add(str(x + 1) + "_" + str(y))
if y > 0:
count.add(str(x) + "_" + str(y - 1))
if y < maxSide:
count.add(str(x) + "_" + str(y + 1))
# 计算得到的气数减去己方棋子的数量
res = len(count)
# 减去敌方棋子占据的气点
for i in range(0, len(enemy), 2):
pos = str(enemy[i]) + "_" + str(enemy[i + 1])
if pos in count:
res -= 1
return res - len(alias) // 2
# 读取黑棋的坐标
locBlacks = parseCoordinates(input())
# 读取白棋的坐标
locWhites = parseCoordinates(input())
# 输出黑棋和白棋的气数,两个数字以空格分隔
print(counting(locBlacks, locWhites), counting(locWhites, locBlacks))
C语言
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
// 定义棋盘大小
#define MAX_SIDE 18
#define MAX_STONES 361 // 最多棋子数(19x19)
// 解析输入的坐标字符串,返回坐标数组
void parseCoordinates(char* input, int* coordinates) {
char* token = strtok(input, " ");
int index = 0;
while (token != NULL) {
coordinates[index++] = atoi(token);
token = strtok(NULL, " ");
}
}
// 检查点是否在数组中
int contains(int x, int y, int* stones) {
for (int i = 0; stones[i] != -1 && i < MAX_STONES * 2; i += 2) {
if (stones[i] == x && stones[i + 1] == y) {
return 1;
}
}
return 0;
}
// 计算棋子的气数
int counting(int* alias, int* enemy) {
int count = 0;
for (int i = 0; alias[i] != -1 && i < MAX_STONES * 2; i += 2) {
int x = alias[i];
int y = alias[i + 1];
int directions[4][2] = {{x-1, y}, {x+1, y}, {x, y-1}, {x, y+1}};
for (int j = 0; j < 4; j++) {
int dx = directions[j][0];
int dy = directions[j][1];
// 检查是否在棋盘内且不被任何棋子占据
if (dx >= 0 && dx <= MAX_SIDE && dy >= 0 && dy <= MAX_SIDE &&
!contains(dx, dy, alias) && !contains(dx, dy, enemy)) {
count++;
}
}
}
return count;
}
int main() {
char line[1024];
int locBlacks[MAX_STONES * 2 + 1], locWhites[MAX_STONES * 2 + 1];
// 初始化数组
memset(locBlacks, -1, sizeof(locBlacks));
memset(locWhites, -1, sizeof(locWhites));
// 读取黑棋的坐标
fgets(line, sizeof(line), stdin);
parseCoordinates(line, locBlacks);
// 读取白棋的坐标
fgets(line, sizeof(line), stdin);
parseCoordinates(line, locWhites);
// 输出黑棋和白棋的气数,两个数字以空格分隔
printf("%d %d\n", counting(locBlacks, locWhites), counting(locWhites, locBlacks));
return 0;
}
解法2
一种骚操作,可忽略
C++
#include <iostream>
#include <sstream>
#include <set>
#include <vector>
using namespace std;
// 最大的棋盘边界索引
static int maxSide = 18;
// 读取棋子的坐标集合
set<int> readChessSet(string line) {
istringstream iss(line);
set<int> chessSet; // 创建一个set来存储坐标
int x, y;
while (iss >> x >> y) { // 解析行坐标和列坐标
// 将坐标转换为一个唯一的整数表示,并添加到集合中
chessSet.insert(x * 19 + y);
}
return chessSet; // 返回包含所有棋子坐标的集合
}
// 计算棋子的气数
int counting(set<int> alias, set<int> enemy) {
// 创建一个新的set,用于存储棋子的气
set<int> count(alias); // 初始包含所有己方棋子的位置
for (int pos : alias) {
int x = pos / 19; // 计算行坐标
int y = pos % 19; // 计算列坐标
// 分别检查上下左右四个方向,如果存在气则添加到集合中
if (x > 0) count.insert((x - 1) * 19 + y);
if (x < maxSide) count.insert((x + 1) * 19 + y);
if (y > 0) count.insert(x * 19 + (y - 1));
if (y < maxSide) count.insert(x * 19 + (y + 1));
}
// 计算得到的气数减去己方棋子的数量
int res = count.size() - alias.size();
// 减去敌方棋子占据的气点
for (int pos : enemy) {
if (count.find(pos) != count.end()) {
res--;
}
}
return res; // 返回最终的气数
}
int main() {
string blackLine, whiteLine;
getline(cin, blackLine); // 读取黑棋的坐标集合
getline(cin, whiteLine); // 读取白棋的坐标集合
set<int> blackSet = readChessSet(blackLine);
set<int> whiteSet = readChessSet(whiteLine);
// 输出黑棋和白棋的气数,两个数字以空格分隔
cout << counting(blackSet, whiteSet) << " " << counting(whiteSet, blackSet) << endl;
return 0;
}
Java
import java.util.Scanner;
import java.util.Set;
import java.util.HashSet;
public class Main {
// 最大的棋盘边界索引
static int maxSide = 18;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
// 读取黑棋的坐标集合
Set<Integer> blackSet = readChessSet(in.nextLine());
// 读取白棋的坐标集合
Set<Integer> whiteSet = readChessSet(in.nextLine());
// 输出黑棋和白棋的气数,两个数字以空格分隔
System.out.println(counting(blackSet, whiteSet) + " " + counting(whiteSet, blackSet));
}
// 读取棋子的坐标集合
static Set<Integer> readChessSet(String line) {
String[] parts = line.split(" "); // 将输入的行按空格分割
Set<Integer> chessSet = new HashSet<>(); // 创建一个HashSet来存储坐标
for (int i = 0; i < parts.length; i += 2) {
int x = Integer.parseInt(parts[i]); // 解析行坐标
int y = Integer.parseInt(parts[i + 1]); // 解析列坐标
// 将坐标转换为一个唯一的整数表示,并添加到集合中
chessSet.add(x * 19 + y);
}
return chessSet; // 返回包含所有棋子坐标的集合
}
// 计算棋子的气数
static int counting(Set<Integer> alias, Set<Integer> enemy) {
// 创建一个新的HashSet,用于存储棋子的气
Set<Integer> count = new HashSet<>(alias); // 初始包含所有己方棋子的位置
for (int pos : alias) {
int x = pos / 19; // 计算行坐标
int y = pos % 19; // 计算列坐标
// 分别检查上下左右四个方向,如果存在气则添加到集合中
if (x > 0) count.add((x - 1) * 19 + y);
if (x < maxSide) count.add((x + 1) * 19 + y);
if (y > 0) count.add(x * 19 + (y - 1));
if (y < maxSide) count.add(x * 19 + (y + 1));
}
// 计算得到的气数减去己方棋子的数量
int res = count.size() - alias.size();
// 减去敌方棋子占据的气点
for (int pos : enemy) {
if (count.contains(pos)) {
res--;
}
}
return res; // 返回最终的气数
}
}
javaScript
// 最大的棋盘边界索引
const maxSide = 18;
// 读取棋子的坐标集合
function readChessSet(line) {
const parts = line.split(' '); // 将输入的行按空格分割
const chessSet = new Set(); // 创建一个Set来存储坐标
for (let i = 0; i < parts.length; i += 2) {
const x = parseInt(parts[i]); // 解析行坐标
const y = parseInt(parts[i + 1]); // 解析列坐标
// 将坐标转换为一个唯一的整数表示,并添加到集合中
chessSet.add(x * 19 + y);
}
return chessSet; // 返回包含所有棋子坐标的集合
}
// 计算棋子的气数
function counting(alias, enemy) {
// 创建一个新的Set,用于存储棋子的气
const count = new Set(alias); // 初始包含所有己方棋子的位置
for (let pos of alias) {
const x = Math.floor(pos / 19); // 计算行坐标
const y = pos % 19; // 计算列坐标
// 分别检查上下左右四个方向,如果存在气则添加到集合中
if (x > 0) count.add((x - 1) * 19 + y);
if (x < maxSide) count.add((x + 1) * 19 + y);
if (y > 0) count.add(x * 19 + (y - 1));
if (y < maxSide) count.add(x * 19 + (y + 1));
}
// 计算得到的气数减去己方棋子的数量
let res = count.size - alias.size;
// 减去敌方棋子占据的气点
for (let pos of enemy) {
if (count.has(pos)) {
res--;
}
}
return res; // 返回最终的气数
}
const readline = require('readline').createInterface({
input: process.stdin,
output: process.stdout
});
readline.on('line', blackLine => {
readline.on('line', whiteLine => {
const blackSet = readChessSet(blackLine); // 读取黑棋的坐标集合
const whiteSet = readChessSet(whiteLine); // 读取白棋的坐标集合
// 输出黑棋和白棋的气数,两个数字以空格分隔
console.log(counting(blackSet, whiteSet) + " " + counting(whiteSet, blackSet));
readline.close();
});
});
Python
maxSide = 18
def readChessSet(line):
parts = line.split(' ')
chessSet = set()
for i in range(0, len(parts), 2):
x = int(parts[i])
y = int(parts[i + 1])
chessSet.add(x * 19 + y)
return chessSet
def counting(alias, enemy):
count = set(alias)
for pos in alias:
x = pos // 19
y = pos % 19
if x > 0: count.add((x - 1) * 19 + y)
if x < maxSide: count.add((x + 1) * 19 + y)
if y > 0: count.add(x * 19 + (y - 1))
if y < maxSide: count.add(x * 19 + (y + 1))
res = len(count) - len(alias)
for pos in enemy:
if pos in count:
res -= 1
return res
# 主方法,程序入口
blackLine = input()
whiteLine = input()
blackSet = readChessSet(blackLine)
whiteSet = readChessSet(whiteLine)
print(counting(blackSet, whiteSet), counting(whiteSet, blackSet))
完整用例
用例1
0 0 0 1 0 2
1 0 2 0 3 0
用例2
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0 17 0
用例3
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0 16 0
用例4
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0 15 0
用例5
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0 13 0 14 0
用例6
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0 12 0
用例7
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0 11 0
用例8
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0 10 0
用例9
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7 0 8
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0 9 0
用例10
0 0 0 1 0 2 0 3 0 4 0 5 0 6 0 7
1 0 2 0 3 0 4 0 5 0 6 0 7 0 8 0
@[TOC]