图搜索 | LCP 41. 黑白翻转棋 *

本文记录的是刷题过程中的重要概念和笔记。如有侵权,请联系删除。

原题

在 n*m 大小的棋盘中,有黑白两种棋子,黑棋记作字母 “X”, 白棋记作字母 “O”,空余位置记作 “.”。当落下的棋子与其他相同颜色的棋子在行、列或对角线完全包围(中间不存在空白位置)另一种颜色的棋子,则可以翻转这些棋子的颜色。

来源:力扣(LeetCode)
链接:https://leetcode.cn/problems/fHi6rV
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

母题

八皇后问题,没有快捷方法,回溯爆搜

方法

广度优先搜索+回溯

对每一个空余位置尝试黑棋放置,用一个队列来存储正在进行「翻转操作」的黑棋位置,若有可以翻转的白棋,则将这些白旗进行翻转,并加入队列中。直至队列为空表示一次放置黑棋结束。

class Solution {
private:
    const int dirs[8][2] = {
        // 1*:将可能的八个方向以字典记录下来,从而实现代码归一化
        {1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}
    };

    bool judge(vector<string>& chessboard, int x, int y, int dx, int dy){
        // 判断该方向是否符合条件
        x+=dx;
        y+=dy;
        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 check(vector<string> chessboard, int x, int y){
// 注意参数:chessboard按值传递,因为不同位置需要更新为原来的棋盘。本质为回溯的改为原值。

        // 回溯算法
        // 终止条件:if(chessboard[x][y]!='.') return 0;
        int res=0;
        // 逐层的遍历通过队列存储,本质上是采用bfs
        queue<pair<int,int>> que;
        // 2*:que.push(pair<int,int>(x,y));注意写法
        que.push(pair<int,int>(x,y));
        while(!que.empty()){
            // 处理当前队首节点
            pair<int, int> tmp = que.front();
            que.pop();
            for(int i=0;i<8;i++){
                if(judge(chessboard,tmp.first,tmp.second,dirs[i][0],dirs[i][1])){
                    int xTmp= tmp.first+dirs[i][0];
                    int yTmp= tmp.second+dirs[i][1];
                    while(chessboard[xTmp][yTmp]!='X'){
                        que.push(pair<int,int>(xTmp,yTmp));
                        chessboard[xTmp][yTmp]='X';
                        xTmp+=dirs[i][0];
                        yTmp+=dirs[i][1];
                        res++;
                    }
                }
            }
        }
        return res;       
    }

public:
    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,check(chessboard,i,j));
            }
        }
        return res;
    }
};

复杂度

在这里插入图片描述

知识点

  • 1*:将可能的八个方向以字典记录下来,从而实现代码归一化
  • 2*:que.push(pair<int,int>(x,y));注意写法

补充

  1. push_back和emplace_back的区别只在传入的参数是对象的构造参数时,如push_back(10),emplace_back(10)。

    两种情况下:
    push_back(10)会先调用类的有参构造函数,创建一个临时对象,再在容器的末尾调用类的右值构造函数(因为这个临时对象没有名字,属于右值,所以只能使用右值构造函数),输入临时对象的地址,创建一个新的对象,根据地址值到临时对象所在的内存空间中拷贝数据,最后再调用临时对象的析构函数,析构这个临时对象。

    emplace_back(10)少了临时对象这一步,直接在容器的末尾调用类的有参构造函数创建一个新的对象,完成添加操作。

版权声明:本文为CSDN博主「Zeehoy」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_44179561/article/details/124387475

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值