力扣 |LCP41黑白翻转棋

92 篇文章 0 订阅
42 篇文章 0 订阅

前情描述:在一个二维棋盘(n*m)棋盘上的每个点只有三种情况,要么是黑子(用'X‘表示)、要么是白子(用'0'表示,注意不是O)、要么是空白(‘.‘表示)

要求当下黑子满足在八个方向是的黑子形成一条直线,这样可以把线中间的白子换成黑子,求最后翻转白子最大个数。

深度遍历,把空白位置置为黑,然后判断是否满足要翻白子为黑子的条件(也就是在8个方向中有与之最近的黑点相连,两黑点之间必然是为黑或者为白,不存在空这种情况

用一个队列存储正在进行【翻转】的黑子位置,若队列不为空,取出队首元素,判断该黑点是否在8个方向上是否有翻转的白子,满足翻转的白子进行翻转,并将该点加入队列,接着判断该点的八个方向是否有可翻转的白子……

可翻转的白子个数最大值极为所求解

class Solution {
public:

    //  黑子 x  白子    0   空白    .
    //
    //            (-1, 1)  (0, 1)  (1, 1)
    //            (-1, 0)  (0, 0)  (1, 0)
    //            (-, -1)  (0,-1)  (1,-1)
    //
    const int dirs[8][2] ={
        {1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}
    };

    //传入 数组 遍历到的黑子的坐标  黑子的八个方位 
    //注意这里为什么引用了呢?  
    bool judge(const vector<string>& chessboard, int x, int y, int dx, int dy){
        x += dx;
        y += dy;
        //遍历棋盘中所有棋子    要在棋盘范围内
        //往八个方向发散,一点点向外发散,一旦找到方位的第一个黑子直接返回true
        while(0 <= x && x < chessboard.size() && 0 <= y && y < chessboard[0].size()){
            if(chessboard[x][y] == 'X'){
                //如果对面是黑子
                return true;
            }else if(chessboard[x][y] =='.'){
                return false;
            }
            //是白子    那么就跳过
            x += dx;
            y += dy;
        }
        return false;
    }

    //注意为什么这里没有引用呢?        每一次遍历都会修改棋盘坐标      每一轮遍历都是不同的棋盘
    int dfs(vector<string> chessboard, int px, int py){
        int cnt = 0;
        queue<pair<int, int>> q;
        //queue 在队列中插入元素(px1, py1), (px2, py2),...
        q.emplace(px, py);
        //需要修改状态 把 . 变成 x
        chessboard[px][py] = 'X';           
        //遍历队列q 
        while(!q.empty()){
            pair<int, int> t = q.front();
            q.pop();
            //检查该点的八个方向
            for(int i = 0; i < 8; ++i){
                //八个射线中与第一个黑点组成一个线段
                if(judge(chessboard, t.first, t.second, dirs[i][0], dirs[i][1])){
                    //在方位内找到第一个黑子,记录方位
                    int x = t.first + dirs[i][0];
                    int y = t.second + dirs[i][1];
                    //方位中多有不是黑点的点都要修改为黑点,且由近到远,
                    //并计数翻转个数(前面已经把空白点涂层黑色了)
                    while(chessboard[x][y] != 'X'){
                        q.emplace(x, y);
                        chessboard[x][y] = 'X';
                        x += dirs[i][0];
                        y += dirs[i][1];
                        ++cnt;
                    }

                }
            }
        }
        return cnt;
    }

    int flipChess(vector<string>& chessboard) {
        //统计黑子移动次数
        int res = 0;
        for(int i = 0; i < chessboard.size(); ++i){
            for(int j = 0; j < chessboard[0].size(); ++j){
                //如果遍历的元素是.说明为空,加入队列
                if(chessboard[i][j] == '.'){
                    res = max(res, dfs(chessboard, i, j));
                }
            }
        }
        return res;
    }
};

ps:要多练这种,多角度结合,完全像一个小游戏了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值