2724:围棋
2724:围棋
题目来源:http://noi.openjudge.cn/ch0308/2724/
2724:围棋
总时间限制: 1000ms 内存限制: 65536kB
描述
围棋的棋盘上有19*19条线交织成的361个交点,黑棋和白棋可以下在交点上。我们称这些交点为“目”。
一个目的上下左右四个方向,称之为“气”,如果一个目的四个方向都被某一种颜色的棋子占据,那么即使这个目上并没有棋子,仍然认为这个目被该颜色棋子占据。
如下图中,四个黑棋中心的交点,由于被黑棋包围,因此我们认为这个目属于黑棋,
黑棋拥有4+1=5目
在棋盘的边框地区,只要占据目的三个方向,就可以拥有这个目。
黑棋拥有3+1=4目
同理在棋盘的四个角上,只要占据目的两个气即可。
黑棋拥有2+1=3目
推而广之,当有多个目互相连通的时候,如果能用一种颜色把所有交点的气都包裹住,那么就拥有所有目。
黑棋拥有6+2 = 8目
请编写一个程序,计算棋盘上黑棋和白棋的目数。
输入数据中保证所有的目,不是被黑棋包裹,就是被白棋包裹。不用考虑某些棋子按照围棋规则实际上是死的,以及互相吃(打劫),双活等情况。
输入
第一行,只有一个整数N(1<=N<=100),代表棋盘的尺寸是N* N
第2~n+1行,每行n个字符,代表棋盘上的棋子颜色。
“.”代表一个没有棋子的目
“B”代表黑棋
“W”代表白棋
输出
只有一行,包含用空格分隔的两个数字,第一个数是黑棋的目数,第二个数是白棋的目数。
样例输入
4
..BW
...B
....
....
样例输出
15 1
————————————————
这个题有个很重要的简化,就是“保证所有的目,不是被黑棋包裹,就是被白棋包裹”,所以其实问题就简化为了求包围着的是白棋还是黑棋,这个比原问题就简单多了。
求包围的话,可以使用bfs从里向外求,遇到黑色或者白色,就说明是黑色的目或者白色的目
代码如下,逻辑很简单:
package com.jiading.noi;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.Scanner;
/*
* 2724:围棋
* http://noi.openjudge.cn/ch0308/2724/
*
*/
public class Problem18 {
// n是棋盘格数,b是黑棋的得分,w是白棋的得分
// 定义在外面作为全局变量,方便函数直接调用
public static int n = 0, b = 0, w = 0;
// 棋盘
public static char[][] mat;
public static void bfs(int i, int j) {
// 最后搜出来的是一片的结果,不是单个点
// cnt其实就是count,不太理解为什么许多人喜欢缩写成这个
// xx,yy是考察点的x,y坐标
int cnt = 0, xx, yy;
// 这一片是不是B的气
boolean is_B = false;
Queue<Integer> qx, qy;
// 放x和y坐标的队列
qx = new ArrayDeque<Integer>();
qy = new ArrayDeque<Integer>();
// 先把当前点放进去
qx.offer(i);
qy.offer(j);
// 当前点就算一个
cnt++;
// 这里的意思是,如果是算过的点就换成一个其他类型的字符,比如这里用的*
mat[i][j] = '*';
while (!qx.isEmpty()) {
// 取一个出来,现在这个点处于未定状态
xx = qx.poll();
yy = qy.poll();
// 如果左面也是未定态
// 这里注意,每次直接就把未定态的点标记为访问过了(*)
if (xx > 0 && mat[xx - 1][yy] == '.') {
mat[xx - 1][yy] = '*';
cnt++;
qx.offer(xx - 1);
qy.offer(yy);
} else if (xx > 0 && mat[xx - 1][yy] == 'B') {
is_B = true;
}
// 只考察了B或者.的情况,因为不是B包裹的话就一定是W,而已访问的点不能计数
// 现在考察上面
if (yy > 0 && mat[xx][yy - 1] == '.') {
mat[xx][yy - 1] = '*';
cnt++;
qx.offer(xx);
qy.offer(yy - 1);
} else if (yy > 0 && mat[xx][yy - 1] == 'B') {
is_B = true;
}
// 右面
if (xx < n - 1 && mat[xx + 1][yy] == '.') {
mat[xx + 1][yy] = '*';
cnt++;
qx.offer(xx + 1);
qy.offer(yy);
} else if (xx < n - 1 && mat[xx + 1][yy] == 'B') {
is_B = true;
}
// 下面
if (yy < n - 1 && mat[xx][yy + 1] == '.') {
mat[xx][yy + 1] = '*';
cnt++;
qx.offer(xx);
qy.offer(yy + 1);
} else if (yy < n - 1 && mat[xx][yy + 1] == 'B') {
is_B = true;
}
}
// 把这一片都加上
if (is_B) {
b += cnt;
} else {
w += cnt;
}
return;
}
public static void main(String[] args) throws IOException {
Scanner scanner = new Scanner(System.in);
// 注意这里要用nextLine而不是next,否则之后再读,读到的就是第一行的换行符而不是第二行
n = Integer.valueOf(scanner.nextLine());
mat = new char[n][n];
// 读棋盘
for (int i = 0; i < n; i++) {
String lineString = scanner.nextLine();
for (int j = 0; j < n; j++) {
mat[i][j] = lineString.charAt(j);
}
}
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (mat[i][j] == '.') {
bfs(i, j);
}
// 如果这个点直接就是B或者W,那就直接加1
else if (mat[i][j] == 'B') {
b++;
} else if (mat[i][j] == 'W') {
w++;
}
}
}
System.out.println(String.valueOf(b) + " " + String.valueOf(w));
}
}

浙公网安备 33010602011771号