首页 > 代码库 > 华为机试—围棋吃子(下围棋)判决(高级题160分:深度优先遍历)(图文吐血整理)

华为机试—围棋吃子(下围棋)判决(高级题160分:深度优先遍历)(图文吐血整理)

题目:

围棋中,一个棋子在棋盘上,与它直接紧邻的空点是这个棋子的“气”,棋子直接紧邻的点上,如果有同色妻子存在,则它们便相互组成一个不可分割的整体,它们的“气”也应一并计算。如果一个或一片棋子的“气”为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;
} 

技术分享

技术分享




华为机试—围棋吃子(下围棋)判决(高级题160分:深度优先遍历)(图文吐血整理)