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:
The first line of input gives the number of test cases, T. T test cases follow. Each test case start with the size of the side of the board, N. 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). Note that the judge is case-sensitive, so answers of "impossible", "blue wins", "red wins" and "nobody wins" will be judged incorrect.
1 ≤ T ≤ 100.
1 ≤ N ≤ 10.
1 ≤ N ≤ 100.
Input |
Output |
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 |
类型:图论 难度:2.5
题意:给出一个n*n的棋盘如上所示,每个网格为一个六边形,和左上,右上,左,右,左下,右下六个格子相邻,上下边界为红色,左右边界为蓝色,红蓝双方依次向棋盘下子,红方将上下边界用红子连起来,或蓝方将左右连起来,游戏立即结束。现给定棋盘上红蓝子的位置,问这个棋局是不可能出现的、红方赢、蓝方赢,还是没人赢?
分析:这题也是做了很久。。先分析4种结果所有可能的情况,其中1(3)这种情况是最难想到的,也是整个题目的难点:
1、棋局不可能出现:
(1)红蓝方棋子数差值大于1。
这个好理解,双方依次下,不可能出现一方比另一方多两个子的情况。
(2)红方赢,但是蓝方棋子多于红方;蓝方情况相同。
红方赢了,那么红方下最后一个子,蓝方不能比红方还多子。
(3)红方赢,但是红方从上边界到下边界的所有通路上没有割点(割点就是去掉这个点,路变成不连通的);蓝方情况相同。
可以理解为,胜者的通路中必须找到一个最后下的子,就是说,在这个子下之前路是不连通的,下了之后变成连通的,游戏结束。若找不到这样的子,证明通路上有多余的子,游戏本该结束,但还在继续。
2、红方赢:
除去1中的情况,红方连通上下边界
3、蓝方赢:
除去1中的情况,蓝方连通左右边界
4、没人赢:
除去1中的情况,红蓝方均为连通
有了上述的分析,实现就容易多了,我实现的稍麻烦一些:以红方为例,对第一行每个红子做dfs(注意是六个方向),做了一个剪枝:从第一行出发的dfs不再回到第一行,只记录往下走能连通的子,若能连通则标记路径上所有子。找到所有通路后,对每个标记的子做如下操作:去掉这个子,再看是否存在通路,若去掉后不存在通路,则找到合法的最后一个子,满足1(3)。1(1),1(2),2,3都比较容易判定,就不赘述了。
代码如下:
#include<cstdio> #include<cstring> #include<iostream> #include<vector> #include<cmath> using namespace std; const int MAX = 110; int n; char mp[MAX][MAX]; int flag[MAX][MAX][2]; bool step[MAX][MAX][2]; int getthrough(int x,int y,int dir,bool isst) { if(step[x][y][dir]) return 0; if(flag[x][y][dir] >= 0) return flag[x][y][dir]; if(dir==0) { if(x<0 || y<0 || y>=n || mp[x][y]!='R') return 0; if(!isst && x<1) return 0; if(x>=n-1) { flag[x][y][dir] = 1; return 1; } } else { if(y<0 || x<0 || x>=n || mp[x][y]!='B') return 0; if(!isst && y<1) return 0; if(y>=n-1) { flag[x][y][dir] = 1; return 1; } } step[x][y][dir] = 1; int ld,rd,l,r,lu,ru; ld = rd = l = r = lu = ru = 0; ld = getthrough(x+1,y-1,dir,0); rd = getthrough(x+1,y,dir,0); l = getthrough(x,y-1,dir,0); r = getthrough(x,y+1,dir,0); lu = getthrough(x-1,y,dir,0); ru = getthrough(x-1,y+1,dir,0); if(lu>0 || ru>0 || l>0 || r>0 || ld>0 || rd>0) flag[x][y][dir] = 1; else flag[x][y][dir] = 0; step[x][y][dir] = 0; return flag[x][y][dir]; } int check() { memset(flag,-1,sizeof(flag)); memset(step,0,sizeof(step)); int bcnt,rcnt,left,right,up,down; bcnt = rcnt = left = right = up = down = 0; for(int i=0; i<n; i++) for(int j=0; j<n; j++) { if(mp[i][j]=='B') bcnt++; else if(mp[i][j]=='R') rcnt++; } if(abs(bcnt-rcnt) > 1) return 0; int redwin,bluewin; redwin = bluewin = 0; for(int i=0; i<n; i++) { if(mp[0][i]=='R') redwin |= getthrough(0,i,0,1); if(mp[i][0]=='B') bluewin |= getthrough(i,0,1,1); } if((redwin && bcnt>rcnt) || (bluewin && rcnt>bcnt)) return 0; if(!redwin && !bluewin) return 3; int tmpflag[MAX][MAX][2]; memcpy(tmpflag,flag,sizeof(flag)); char winc = 0; int dir = -1; if(redwin) { winc = 'R'; dir = 0; } if(bluewin) { winc = 'B'; dir = 1; } for(int i=0; i<n; i++) { for(int j=0; j<n; j++) { if(tmpflag[i][j][dir]==1) { mp[i][j] = '.'; int tmpw = 0; memset(flag,-1,sizeof(flag)); memset(step,0,sizeof(step)); for(int i=0; i<n; i++) { if(dir==0 && mp[0][i]=='R') tmpw |= getthrough(0,i,0,1); if(dir==1 && mp[i][0]=='B') tmpw |= getthrough(i,0,1,1); } mp[i][j] = winc; if(tmpw==0) return dir+1; } } } return 0; } int main() { freopen("C-large-practice.in","r",stdin); freopen("C-large-practice.out","w",stdout); int t; scanf("%d",&t); for(int cnt=1; cnt<=t; cnt++) { scanf("%d",&n); memset(mp,0,sizeof(mp)); for(int i=0; i<n; i++) scanf("%s",mp[i]); int ans = check(); printf("Case #%d: ",cnt); if(ans == 0) printf("Impossible\n"); else if(ans == 1) printf("Red wins\n"); else if(ans == 2) printf("Blue wins\n"); else printf("Nobody wins\n"); } }