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));
	}
}
posted @ 2020-06-26 18:12  别再闹了  阅读(394)  评论(0)    收藏  举报