华为机试—围棋吃子(下围棋)判决(高级题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;
} 

时间: 2024-10-12 22:27:49

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

华为机试—N皇后问题(高级题160分:两种回溯法解决 吐血整理)

一.问题描述: 在n×n格的棋盘上放置彼此不受攻击的n个皇后.按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子.n后问题等价于再n×n的棋盘上放置n个皇后,任何2个皇后不妨在同一行或同一列或同一斜线上. 输入: 给定棋盘的大小n (n ≤ 13) 输出: 输出有多少种放置方法. 二.解题思路: 要解决N皇后问题,其实就是要解决好怎么放置这n个皇后,每一个皇后与前面的所有皇后不能在同一行.同一列.同一对角线,在这里我们可以以行优先,就是说皇后的行号按顺序递增,只考虑第i个皇

华为机试—计算麻将的番数(高级题160分)

一.题目如下 二.题目分析 麻将和牌有两种形式,即: 模式1 :11,11,11,11,11,11,11 模式2: 11,123,123,123,123(全部或者部分123可以被111,1111替代) 注:123=连续3张同花色牌,如4D5D6D.111=3张同样的牌,如3T3T3T. 条=T,筒=D 模式1即称之为"巧7对",一组牌刚好是7对牌.但是这里有一个疑问,"对"能否重复,即"杠"能否能当作2"对"(即题目中的&qu

华为机试—物品放箩筐(高级题160分,含体积价值:贪心算法)

#include <iostream> using namespace std; int m[100][100]; int min(int a,int b) { return (a<b)?a:b; } int max(int a,int b) { return (a>b)?a:b; } void knapsack(int v[],int w[],int c,int n) { int jMax=min(w[n],c); for(int j=0;j<=jMax;j++) m[n]

华为机试—添加符号使等式成立(高级题160分)

输入一个正整数X,在下面的等式左边的数字之间添加+号或者-号或者不填,使得等式成立. 1 2 3 4 5 6 7 8 9 = X 比如: 12-34+5-67+89 = 5 1+23+4-5+6-7-8-9 = 5 请编写程序,统计满足输入整数的所有等式个数. 输入:       正整数,等式右边的数字 输出:       使该等式成立的个数 样例输入:5 样例输出:21 #include <iostream> #include <string> using namespace s

华为机试—取石子游戏(高级题160分)

Problem Description 1堆石子有n个,两人轮流取.先取者第1次可以取任意多个,但不能全部取完.以后每次取的石子数不能超过上次取子数的2倍.取完者胜.先取者负输出"Secondwin".先取者胜输出"Firstwin". Input 输入有多组.每组第1行是2<=n<2^31.n=0退出. Output 先取者负输出"Secondwin". 先取者胜输出"Firstwin". 参看Sample Ou

华为机试—介绍、剖析、建议

一.华为机试介绍 1.大致介绍 时间:120分钟 环境:Visual Studio(去年是vs2005).Visual C++.VC 6.0.Eclipse(Java) 题量:共3题 初级题--60分--3组测试数据 中级题--100分--5组测试数据 高级题--160分--8组测试数据 注:初级题和中级题为必答题,高级题为附加题. 提交次数:每题最多5次 评判方式:按通过测试数据组数给分,每通过一组得20分 2.考试说明 这里有一个老版的机试考试说明,供大家参考: C/C++,JAVA机试流程

2014华为机试西安地区A组试题

2014华为机试西安地区A组试题 题目一.分苹果 M个相同苹果放到N个相同篮子里有多少种放法,允许有篮子不放. 1<=M<=10,1<=N<=10 例如5个苹果三个篮子,3,1,1 和 1,1,3是同一种放法 输入 7 3 输出 8 题目分析: 这道题类似于整数划分的题目,这是很早的一道ACM的题目,主要思路就是考递归. ①当苹果数目或者篮子数目为1时候,就只有一种可能 ②当苹果数目小于篮子数目的时候,按照苹果数目来分配 ③当苹果数目大于篮子数目的时候,空一个盘子 + 先每个盘子放

[华为机试]输入数字的汉语拼音,每个拼音的首字母大写。输出该数字的阿拉伯数字。

//输入数字的汉语拼音,每个拼音的首字母大写.输出该数字的阿拉伯数字. //JiuBaiJiuShiJiu -> 999 #include<stdio.h> #include<string.h> int result = 0; void add(int n,char wei[]) { if(strcmp(wei,"Wan") == 0) result = result + n * 10000; else if(strcmp(wei,"Qian&q

华为机试(5)

中级题  题目描述  你有一个容量为100的箩筐,给你30个物品,每个物品的体积已知问:最多能装多少个物品进箩筐  输入描述  :一行30个正整数,用空格隔开,表示每个物品的体积  输出描述  :一个数字,为最多能装下的物品数 输入样例(此处用3个物品作为样例,实际读入为30个)  :5 59 100  输出样例  :2 解题思路:利用性价比对所有物品进行排序,优先装性价比高的,在此题中,性价比就是物品的体积 #include<algorithm>//sort函数 #include<io