166.数独

复制代码
#include <iostream>
#include <algorithm>
#include <stdlib.h>
#include <string>
using namespace std;

const int N = 9, M = 1 << N;

char str[100];
int Row[N], Line[N], Block[3][3]; // 哪些数字可以填, 1可以填写, 0 不能填写
int Log[M], cnt[M], Empty;

void Deal(int x, int y, int num, int f)
{
    if (f < 0)
        str[x * 9 + y] = num + '1';
    else
        str[x * 9 + y] = '.';
    int Target = (1 << num) * f;
    Row[x] += Target;
    Line[y] += Target;
    Block[x / 3][y / 3] += Target;
}

int query(int x, int y)
{
    int tmp = Row[x] & Line[y] & Block[x / 3][y / 3];
    return cnt[tmp];
}

int lowbit(int x)
{
    return x & (-x);
}

bool dfs(int Done)
{
    if (Done == 0)
    {
        return true;
    }
    int tx = -1, ty = -1, m = 0x3f3f3f3f;
    for (int i = 0; i < 9; i++)
        for (int j = 0; j < 9; j++)
        {
            if(str[i * 9 + j] != '.') continue;
            int tmp = query(i, j);
            if (tmp < m)
            {
                m = tmp;
                tx = i;
                ty = j;
            }
        }
    int State = Row[tx] & Line[ty] & Block[tx / 3][ty / 3];
    for(int i = State; i; i -= lowbit(i))
    {
        int tmp = lowbit(i);
        int Pos = Log[tmp];
        Deal(tx, ty, Pos, -1);
        if(dfs(Done - 1)) return true;
        Deal(tx, ty, Pos, 1);
    }
    return false;
}

void init()
{
    for (int i = 0; i < N; i++)
        Row[i] = Line[i] = (1 << N) - 1;
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            Block[i][j] = (1 << N) - 1;
}

int main()
{
    for (int i = 0; i < N; i++)
        Log[1 << i] = i;
    for (int i = 0; i < M; i++)
        for (int j = 0; j < N; j++)
            cnt[i] += i >> j & 1;
    while (cin >> str && str[0] != 'e')
    {
        init();
        Empty = 0;
        for (int i = 0, Now = 0; i < 9; i++)
            for (int j = 0; j < 9; j++, Now++)
            {
                if (str[Now] != '.')
                    Deal(i, j, str[Now] - '1', -1);
                else
                    Empty++;
            }
        dfs(Empty);
        puts(str);
    }
    return 0;
}
复制代码

写的时候太马虎大意了,dfs忘记加最重要的判断语句:

if(str[i * 9 + j] != '.') continue;

导致一直搜不出来

一开始想用每一位数的0表示没填过(即还可以填)  1反之

但写到一半才意识到这种写法是不可取的

因为如果这么写的话,为了配合lowbit运算,我们就需要对得到的结果数字进行取反。

但是我们的cnt数组只处理了0~1 << N 范围内的数字,取反之后会超出这个范围,导致计算出错,甚至产生segment fault

 

这道题还有个值得注意的点:

因为这道题不是找最优解或者统计方案数,所以不能写成void(void形式最终会找到所有的可行解,可能会TLE)

这道题需要写成bool形式,一旦当前搜索树的一棵子树找到了答案,就没有必要再继续搜索它的其他子树了,因为我们只需要一个可行解即可。

本文作者:Gold_stein

本文链接:https://www.cnblogs.com/smartljy/p/17826609.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   Gold_stein  阅读(14)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
💬
评论
📌
收藏
💗
关注
👍
推荐
🚀
回顶
收起
🔑
  1. 1 逃离地面 RAD & 三浦透子
逃离地面 - RAD & 三浦透子
00:00 / 00:00
An audio error has occurred.

作词 : 野田洋次郎

作曲 : 野田洋次郎

空飛ぶ羽根と引き換えに 繋ぎ合う手を選んだ僕ら

それでも空に魅せられて 夢を重ねるのは罪か

夏は秋の背中を見て その顔を思い浮かべる

憧れなのか、恋なのか 叶わぬと知っていながら

重力が眠りにつく 1000年に一度の今日

太陽の死角に立ち 僕らこの星を出よう

彼が眼を覚ました時 連れ戻せない場所へ

「せーの」で大地を蹴って ここではない星へ

行こう

もう少しで運命の向こう もう少しで文明の向こう

もう少しで運命の向こう もう少しで

夢に僕らで帆を張って 来たるべき日のために夜を超え

いざ期待だけ満タンで あとはどうにかなるさと 肩を組んだ

怖くないわけない でも止まんない

ピンチの先回りしたって 僕らじゃしょうがない

僕らの恋が言う 声が言う

「行け」と言う