题目:
围棋中,一个棋子在棋盘上,与它直接紧邻的空点是这个棋子的“气”,棋子直接紧邻的点上,如果有同色妻子存在,则它们便相互组成一个不可分割的整体,它们的“气”也应一并计算。如果一个或一片棋子的“气”为0,那它们将被吃掉。
1. 一个棋子的情况,如下左图,白棋右侧还有一个空点,此时白棋气为1,不会被吃掉。当黑棋在此空点下棋后,白棋气为0,将被吃掉。
2. 一片棋子的情况,如下图,左下角的白棋下面有一个空点,由于其它白棋都与之能通过直接相邻,此时整片白棋的气都为1,不会被吃掉。当黑棋在该空点下棋后,白棋气为0,将被吃掉。
3. 当下棋造成双方棋子都没有气时,只有对方的棋子被吃掉。如下图空点处,黑棋下子后,最中间的黑棋和中圈的白棋都没有气,但只有白棋被吃掉。除了这种情况。不允许下棋导致本方棋子没有气(自杀棋)。
本题用一个10x10的二维数组表示棋盘,数组中0表示空点,1表示白棋,2表示黑棋 。棋盘左下角为(0,0),右上角为(9,9),水平为x方向,竖直为y方向。
为避免走棋步数太多,提供设置棋盘的接口可以将棋盘初始化为一个残局状态。之后不断进行下棋,下棋顺序不定,可以连续下黑或者连续下白(围棋允许一方放弃下子)当棋子吃掉后,返回相应的吃子情况外,还应将被吃棋子从棋盘中移除,保证棋盘状态正确。
运行时间限制:无限制
内存限制:无限制
输入:输入一个10*10的整数,初始化棋盘。输入保证初始化的残局中不存在气为0的子(即被吃棋子却没取走的异常状态)。输入一行或多行整数,每行3个整数,分别表示,所下棋子的x位置,y位置,棋子类型(1表示白棋,2表示黑棋)。
输出:一个整数。含义如下:
0:本次下棋未发生吃子
2147483647下棋错误(该位置已有棋子,或下棋导致本方棋子无气)
其余正值:有白棋被吃掉,吃掉个数等于返回值
负值:有黑棋被吃掉,吃掉个数等于返回值的绝对值
解析:
当给定一个输入时,我们首先判断下的这个棋子是否导致自身的棋子没气;然后判断下的这个棋子是否导致对方的棋子没气,并统计没气的棋子的个数;若对方没有棋子没气,但自身有棋子没气了,则为违规输入;否则,返回对方没气的棋子的个数即可。
那么这里关键问题便是如何判断是否有棋子没气了。这个问题可以用典型的dfs(深度优先)的方法来解决。给定一个位置以及该位置的棋子类型,我们首先判断该棋子上方是否为空,若为空,则表示与该棋子位置相连的相同棋子均有气;若上方棋子为相同颜色的棋子,则递归到该位置继续判断;若上方位置为对方棋子,则表示该棋子上方没有气。在遍历玩该棋子的上方能够遍历的位置之后,发现没有找到气,则选择其他方向继续遍历。直到一个方向找到了气,或是四个方向均没有气。
#include <iostream> using namespace std; int A[10][10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 2, 1, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; bool B[10][10]; int eatCount = 0; //初始化矩阵B都为false void initFlagMatrix() { for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) B[i][j] = false; } } bool hasAir(int i, int j, int type) { if(A[i][j] == 0) return true; if(A[i][j] != type) return false; eatCount++; B[i][j] = true; if(i > 0 && !B[i-1][j] && hasAir(i-1, j, type)) return true; else if(i < 9 && !B[i+1][j] && hasAir(i+1, j, type)) return true; else if(j > 0 && !B[i][j-1] && hasAir(i, j-1, type)) return true; else if(j < 9 && !B[i][j+1] && hasAir(i, j+1, type)) return true; else return false; } //将与A[i][j]相连的相同类型的棋子全部吃掉 void eatChess(int i, int j, int type) { if(A[i][j] != type) return; A[i][j] = 0; //吃掉子 if(i > 0) eatChess(i-1, j, type); if(i < 9) eatChess(i+1, j, type); if(j > 0) eatChess(i, j-1, type); if(j < 9) eatChess(i, j+1, type); } //查找整个棋盘看棋子是否有气 bool hasAirOfType(int type, int &p, int &q) { for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { if(A[i][j] != type || B[i][j]) continue; eatCount = 0; if(!hasAir(i, j, type)) { p = i, q = j; return false; } } } return true; } //当位置[i,j]放个黑白子的时候吃掉子的个数 int eatenChesscount(int i, int j, int type) { initFlagMatrix(); bool self_hasAir = hasAir(i, j, type); eatCount = 0; int p = 0, q = 0; int other_type = (type==1?2:1); initFlagMatrix(); bool other_hasAir = hasAirOfType(other_type, p, q); if(!self_hasAir && other_hasAir)//自杀 { A[i][j] = 0; return 2147483647; } if(!other_hasAir) { eatChess(p, q, other_type); if(other_type == 1) //白子正数 return eatCount; else //黑子负数 return 0-eatCount; } return 0; } //打印10*10矩阵的残局状态 void printChessState() { for(int i = 0; i < 10; i++) { for(int j = 0; j < 10; j++) { cout << A[i][j] << " "; } cout << endl; } } int main() { int i, j, type; while(cin >> i >> j >> type) { if(A[i][j] != 0) { cout << "2147483647" << endl; continue; } A[i][j] = type; cout<<"当前的残局状态:"<<endl; printChessState(); cout << "此次吃子个数:"<< eatenChesscount(i, j, type) << endl; cout<<"吃子后残局状态"<<endl; printChessState(); } return 0; }