算法竞赛进阶指南——0x22【深度优先搜索】

在这里插入图片描述

牛客一道小栗子 Sudoku
DFS+状态压缩+lowbit运算

#pragma GCC optimize(3, "Ofast", "inline")
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
const int N = 9, M = 1 << 9, mod = 2147483647;
const int inf = 0x3f3f3f3f, eps = 1e-6;
#define IOS                  \
    ios::sync_with_stdio(0); \
    cin.tie(0);              \
    cout.tie(0)
int cnt;
int row[N], col[N], cell[N], num[M], has[M];
char str[81];
inline int lowbit(int x) { return x & -x; }
inline void init() //初始化全为1【0表示填了,1表示未填】
{
    for (int i = 0; i < N; i++)
        row[i] = col[i] = cell[i] = (1 << N) - 1;
}
inline int get(int x, int y) { return row[x] & col[y] & cell[x / 3 * 3 + y / 3]; }
inline bool dfs(int cnt)
{
    if (cnt == 0)
        return 1;
    int miv = 10, x, y;
    for (int i = 0, k = 0; i < N; i++)
        for (int j = 0; j < N; j++, k++)
            if (str[k] == '.') //
            {
                int t = num[get(i, j)]; //找出剩余可填的数的个数
                if (t < miv)
                    miv = t, x = i, y = j;
            }
    for (int i = get(x, y); i; i -= lowbit(i)) //依次尝试剩余能填的数
    {
        int t = has[lowbit(i)];
        row[x] -= 1 << t;
        col[y] -= 1 << t;
        cell[x / 3 * 3 + y / 3] -= 1 << t;
        str[x * 9 + y] = t + '1'; //第i行j列对应正好是第i*9+j个格子
        if (dfs(cnt - 1))
            return 1;
        //还原现场
        row[x] += 1 << t;
        col[y] += 1 << t;
        cell[x / 3 * 3 + y / 3] += 1 << t;
        str[x * 9 + y] = '.';
    }
    return 0;
}
int main()
{
    IOS;
    for (int i = 1; i < M; i++)            //
        for (int j = i; j; j -= lowbit(j)) //找出i总共有几位是1
            num[i]++;
    for (int i = 0; i < N; i++)
        has[1 << i] = i; //找出第几位是1
    while (cin >> str, str[0] != 'e')
    {
        init();
        int cnt = 0; //
        for (int i = 0, k = 0; i < N; i++)
            for (int j = 0; j < N; j++, k++)
                if (str[k] != '.')
                { //以9个为一个单位
                    int x = str[k] - '1';
                    row[i] -= 1 << x;
                    col[j] -= 1 << x;
                    cell[i / 3 * 3 + j / 3] -= 1 << x; //表示第x个数已经填了
                }
                else
                    cnt++;
        dfs(cnt); //在循环里面
        cout << str << endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

WTcrazy _

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值