AcWing 166.数独

这道题一看起来就很麻烦,但是可以用bitset进行优化

暴力搜索就是了

代码如下:

#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3, "Ofast", "inline")
#include<cstdio>
#include<cstring>
#include<bitset>
using namespace std;

const int maxn = 10;
bitset<maxn> r[maxn], c[maxn], b[maxn];
int N, G[maxn][maxn];

inline void init(void){
    memset(G, 0, sizeof(G));
    N = 0;
    for(int i = 0; i < maxn; i++){
        r[i].set(); c[i].set(); b[i].set();
    }
}
bool dfs(int n){
    if(n == N) return true;
    //寻找最少的
    int minv = 10, id = 100;
    for(int i = 0; i < 9; i++)
        for(int j = 0; j < 9; j++)
            if(G[i][j] == 0){
                int num = (r[i] & c[j] & b[(j / 3) + (i / 3) * 3]).count();
                if(num == 0) return false;
                if(num < minv){minv = num; id = i * 9 + j;}
            }
    int rr = id / 9, cc = id % 9; bitset<maxn> x = r[rr] & c[cc] & b[(cc / 3) + (rr/ 3) * 3];
    for(int i = 1; i <= 9; i++){
        if(x.test(i)){
            r[rr].reset(i); c[cc].reset(i); b[(cc / 3) + (rr/ 3) * 3].reset(i); G[rr][cc] = i;
            if(dfs(n + 1)) return true;
            r[rr].set(i); c[cc].set(i); b[(cc / 3) + (rr/ 3) * 3].set(i); G[rr][cc] = 0;
        }
    }
    return false;
}
inline void output(void){
    for(int i = 0; i < 9; i++)
        for(int j = 0; j < 9; j++){
            printf("%d", G[i][j]);
        }
    putchar('\n');
}

int main(void)
{
    char _c;
    while(true){
        if((_c = getchar()) =='e') break;
        init();
        for(int i = 0; i < 81; i++){
            if(_c != '.'){
                int rr = i / 9, cc = i % 9;
                r[rr].reset(_c - '0'); c[cc].reset(_c - '0');
                b[(cc / 3) + (rr/ 3) * 3].reset(_c - '0');
                G[rr][cc] = _c - '0';
            }
            else N++;
            _c = getchar();
        }
        dfs(0);
        output();
    }

    return 0;
}

其中,对于在某一个位置填入数的时候r,c,b的变化可以写在函数里,使程序更加规整

而r[i]代表第i行,能填入的数是哪些,如果能填入则相应的二进制位为1

c代表行的,b代表块的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值