【算法学习笔记】76.DFS 回溯检测 SJTU OJ 1229 mine

本文深入探讨了扫雷游戏中的搜索算法,对比了从后向前进行深度优先搜索的方法,并提出了一种更高效的01枚举策略。通过枚举每个位置是否有地雷,确保每个数字的填写合理,从而避免了复杂的情况处理,显著提高了解题效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

扫雷玩得好还是有点好处的......

这个题一开始像从后向前按照第一排的数字进行DFS 发现自己真傻,先不说这种情况下每个数字的填写情况很多, 还要处理相邻位置的问题。

所以可以对每一位有没有地雷进行枚举。处理每一位的时候,要保证上一个数字是合理的,否则不用进行下去了,类似回溯,注意have变量的处理就好了。

#include <iostream>
#include <stack>
using namespace std;
//最长 暗示dfs
//遇到3 和 0 其实只有一种情况
//遇到2 和 1 有三种情况
//遇到* 有 2+2*3 = 8种情况,
//可见如果以数字为dfs的条件的话 很麻烦 还不如直接用0 1 来枚举每个炸弹的位置
//其实如果数据小的话 可以直接遍历所有可能解 然后进行验证 但是因为n过大,全部情况根本没有办法枚举完,另外就是验证的效率很低
//所以还是dfs

int n;
string nums;
bool isMine[100000+10]={false};
void init(){
    cin>>n;
    cin>>nums;
}
bool have = false;

int alreadyHave(int cur){
    int res = 0;
    res += isMine[cur];
    if(cur>0)
        res += isMine[cur-1];
    if(cur<n-1)
        res += isMine[cur+1];
    return res;
}

bool canPut(int cur){
    if(nums[cur]=='*')
        return true;
    else
        return ('0' + alreadyHave(cur) ) <= nums[cur];
}
bool exactPut(int cur){
    if(nums[cur]=='*')
        return true;
    else
        return ('0' + alreadyHave(cur) ) == nums[cur];
}

void dfs(int cur){
    if(have)
        return;
    if(cur<0){
        have = exactPut(0);
        return;
    }
    isMine[cur] = true;
    if((cur == n-1 and canPut(cur))
       or (cur<n-1 and exactPut(cur+1)) )
        dfs(cur-1);

    if(have)//不必继续
        return;

    isMine[cur] = false;
    if((cur == n-1 and canPut(cur))
       or (cur<n-1 and exactPut(cur+1)) )
        dfs(cur-1);
    return;
}


void build(){

    dfs(n-1);
    int ans = 0;
    for (int i = 0; i < n; ++i)
    {
        if(isMine[i])
            ans++;
    }
    cout<<ans<<endl;
    for (int i = 0; i < n; ++i)
    {
        cout<<isMine[i];
    }
    cout<<endl;
}

int main(int argc, char const *argv[])
{
    init();
    build();
    return 0;
}

 

转载于:https://www.cnblogs.com/yuchenlin/p/sjtu_oj_1229.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值