【数据结构+算法】浙传OJ Contest 2290:13信息1 Java 6 问题 F: Hexagon Game

问题 F: Hexagon Game

时间限制: 1 Sec   内存限制: 128 MB
提交: 5   解决: 2
[ 提交][ 状态][ 讨论版]

题目描述

This problem was inspired by a board game called Hex, designed independently by Piet Hein and John Nash. It has a similar idea, but does not assume you have played Hex. This game is played on an NxN board, where each cell is a hexagon. There are two players: Red side (using red stones) and Blue side (using blue stones). The board starts empty, and the two players take turns placing a stone of their color on a single cell within the overall playing board. Each player can place their stone on any cell not occupied by another stone of any color. There is no requirement that a stone must be placed beside another stone of the same color. The player to start first is determined randomly (with equal probability among the two players). The upper side and lower sides of the board are marked as red, and the other two sides are marked as blue. The goal of the game is to form a connected path of one player's stones connecting the two sides of the board that have that player's color. The first player to achieve this wins. Note that the four corners are considered connected to both colors. The game ends immediately when one player wins. Given a game state, help someone new to the game determine the status of a game board. Say one of the following: "Impossible": If it was impossible for two players to follow the rules and to have arrived at that game state. "Red wins": If the player playing the red stones has won. "Blue wins": If the player playing the blue stones has won. "Nobody wins": If nobody has yet won the game. Note that a game of Hex can't end without a winner! Note that in any impossible state, the only correct answer is "Impossible", even if red or blue has formed a connected path of stones linking the opposing sides of the board marked by his or her colors. Here's a an example game on a 6x6 gameboard where blue won. Blue was the first player to move, and placed a blue stone at cell marked as 1. Then Red placed at cell 2, then blue at cell 3, etc. After the 11th stone is placed, blue wins.

输入要求

The first line of input gives the number of test cases, T(1 ≤ T ≤ 100)T test cases follow.

Each test case start with the size of the side of the board, N(1 ≤ N ≤ 100).

This is followed by a board of N rows and N columns consisting of only 'B', 'R' and '.' characters.

'B' indicates a cell occupied by blue stone, 'R' indicates a cell occupied by red stone, and '.' indicates an empty cell.

输出要求

For each test case, output one line containing "Case #x: y", where x is the case number (starting from 1) and y is the status of the game board.

It can be "Impossible", "Blue wins", "Red wins" or "Nobody wins" (excluding the quotes).

假如输入

7
1
.
1
B
1
R
2
BR
BB
4
BBBB
BBB.
RRR.
RRRR
4
BBBB
BBBB
RRR.
RRRR
6
......
..R...
BBBBBB
..R.R.
..RR..
......

应当输出

Case #1: Nobody wins
Case #2: Blue wins
Case #3: Red wins
Case #4: Impossible
Case #5: Blue wins
Case #6: Impossible
Case #7: Blue wins

提示


1、首先进行六边形棋盘与矩形的转换:
关于方向上的问题解决方案如下:
如上图所示,以6为中心,在矩形内本该有上、下、左、右、左上、左下、右上、右下8个遍历方向,由于六边形六条边面的特性(只与周围其他六个六边形相连),即没有左上和右下的方向。
2、获胜的条件:
(1)所给的棋盘状态下的棋子摆放合理:
(i)按照每人每次轮流下一步的规则,两种颜色的棋子总数最多相差一个,或者相等。
(ii)按照规则,一旦有一方获胜游戏即刻停止。即不可能出现某一方获胜两次及以上,或者,两方都获胜的情况。
(2)对于红方:红色棋子将棋盘的上下边相连。
 对于蓝方:蓝色棋子将棋盘的左右边相连。
注:本来应该先判断棋盘上的棋子布局是否合理,但是检查合理性会很费时,应当先检查输赢或者与检查输赢一起进行。

源码:
import java.util.Scanner;

public class Main {
	
	//定义四种游戏最终状态,并与RESULT里的字符串一一对应
	public static final int BLUE_WINS = 0;
	public static final int IMPOSSIBLE = 1;
	public static final int RED_WINS = 2;
	public static final int NOBODY_WINS = 3;
	
	public static final String[] RESULT = { "Blue wins", "Impossible",
			"Red wins", "Nobody wins" };

	//蓝方和红方赢得比赛的次数
	public static int blueWinCount = 0;
	public static int redWinCount = 0;
	
	/**
	 * 判断双方的棋子数量是否合理(双方棋子数量的差的绝对值不超过1),因为是轮流每人下一颗棋
	 * @param map
	 * @return
	 */
	private static boolean isCellNumberReasonable(char[][] map) {
		int bCount = 0, rCount = 0;
		for (int i = 0; i < map.length; i++) {
			for (int j = 0; j < map.length; j++) {
				if (map[i][j] == 'B') {
					bCount++;
				} else if (map[i][j] == 'R') {
					rCount++;
				}
			}
		}
		// System.out.println("CountCha=" + Math.abs(bCount - rCount));
		return Math.abs(bCount - rCount) <= 1;
	}

	/**
	 * 判断蓝方是否赢得比赛
	 * @param map
	 * @param x
	 * @param y
	 * @return
	 */
	public static boolean isBlueWin(char[][] map, int x, int y) {
		map[x][y] = '.';//将遍历过的位置改为“.”,防止出现循环遍历的情况
		if (y == map.length - 1) {
			blueWinCount++;
		}
		// UP
		if (y - 1 >= 0 && map[x][y - 1] == 'B') {
			isBlueWin(map, x, y - 1);
		}
		// RIGHT_UP
		if (x + 1 < map.length && y - 1 >= 0 && map[x + 1][y - 1] == 'B') {
			isBlueWin(map, x + 1, y - 1);
		}
		// RIGHT
		if (x + 1 < map.length && map[x + 1][y] == 'B') {
			isBlueWin(map, x + 1, y);
		}
		// DOWN
		if (y + 1 < map.length && map[x][y + 1] == 'B') {
			isBlueWin(map, x, y + 1);
		}
		// LEFT_DOWN
		if (x - 1 >= 0 && y + 1 < map.length && map[x - 1][y + 1] == 'B') {
			isBlueWin(map, x - 1, y + 1);
		}
		// LEFT
		if (x - 1 >= 0 && map[x - 1][y] == 'B') {
			isBlueWin(map, x - 1, y);
		}
		return blueWinCount >= 1;

	}

	/**
	 * 判断红方是否赢得比赛
	 * @param map
	 * @param x
	 * @param y
	 * @return
	 */
	private static boolean isRedWin(char[][] map, int x, int y) {
		map[x][y] = '.';//将遍历过的位置改为“.”,防止出现循环遍历的情况
		if (x == map.length - 1) {
			redWinCount++;
		}
		// UP
		if (y - 1 >= 0 && map[x][y - 1] == 'R') {
			isRedWin(map, x, y - 1);
		}
		// RIGHT_UP
		if (x + 1 < map.length && y - 1 >= 0 && map[x + 1][y - 1] == 'R') {
			isRedWin(map, x + 1, y - 1);
		}
		// RIGHT
		if (x + 1 < map.length && map[x + 1][y] == 'R') {
			isRedWin(map, x + 1, y);
		}
		// DOWN
		if (y + 1 < map.length && map[x][y + 1] == 'R') {
			isRedWin(map, x, y + 1);
		}
		// LEFT_DOWN
		if (x - 1 >= 0 && y + 1 < map.length && map[x - 1][y + 1] == 'R') {
			isRedWin(map, x - 1, y + 1);
		}
		// LEFT
		if (x - 1 >= 0 && map[x - 1][y] == 'R') {
			isRedWin(map, x - 1, y);
		}
		return redWinCount >= 1;
	}

	/**
	 * 得到最终结果
	 * 
	 * @param map
	 * @return
	 */
	public static int judge(char[][] map) {
		int n = map.length;
		int state = NOBODY_WINS;
		// 由于isBlueWin和isRedWin两个方法会修改map里的数据,所以要提前判断棋子数量书否合理
		boolean isCellNumberReasonable = isCellNumberReasonable(map);
		for (int i = 0; i < n; i++) {
			if (map[i][0] == 'B' && isBlueWin(map, i, 0)) {
				state = BLUE_WINS;
			}
			if (map[0][i] == 'R' && isRedWin(map, 0, i)) {
				state = RED_WINS;
			}
		}
		// 如果蓝方和红方赢得比赛的次数超过1,或者,棋子数量不合理,则判定游戏当前状态为impossible
		if (blueWinCount + redWinCount > 1 || !isCellNumberReasonable) {
			state = IMPOSSIBLE;
		}
		// System.out.println("WinCount=" + (blueWinCount + redWinCount));
		return state;
	}

	public static void main(String[] args) {
		Scanner cin = new Scanner(System.in);
		int z = cin.nextInt();
		for (int j = 1; j <= z; j++) {
			int n = cin.nextInt();
			char[][] map = new char[n][n];
			for (int i = 0; i < map.length; i++) {
				map[i] = cin.next().toCharArray();
			}

			// 每次初始化蓝方和红方赢得比赛的次数
			blueWinCount = 0;
			redWinCount = 0;

			System.out.println("Case #" + j + ": " + RESULT[judge(map)]);
		}
	}
}

#算法有Bug,日后再改。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值