1 条题解

  • 0
    @ 2025-4-24 20:18:31
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 9;
    int row[N], col[N], cell[3][3];
    string str;
    int ones[1 << N], mp[1 << N]; 
    //ones数组得到二进制数1的个数,mp得到二进制数下任何一个位置的1能填的数字是几
    
    int lowbit(int x)
    {
        return x & -x;
    }
    
    void init()
    {
        for(int i = 0; i < N; i++) row[i] = col[i] = (1 << N) - 1;
        for(int i = 0; i < 3; i++)
            for(int j = 0; j < 3; j++)
                cell[i][j] = (1 << N) - 1;
    }
    
    int get(int x, int y)
    {
        return row[x] & col[y] & cell[x / 3][y / 3];
    }
    
    bool dfs(int cnt)
    {
        if(cnt == 0) return true;
    
        //找到可填数字最少的点
        int minv = 10;
        int x, y;
        for(int i = 0; i < N; i++)
            for(int j = 0; j < N; j++)
                if(str[i * 9 +  j] == '.')
                {
                    int t = ones[get(i, j)];
                    if(t < minv)
                    {
                        minv = t;
                        x = i, y = j;
                    }
                }
    
        //该点枚举所有能填的数字
        for(int i = get(x, y); i; i -= lowbit(i)) // i = 101000100
        {
            int t = mp[lowbit(i)]; 
    
            //修改
            row[x] -= 1 << t;
            col[y] -= 1 << t;
            cell[x / 3][y / 3] -= 1 << t;
            str[x*9 + y] = '1' + t;
    
            if(dfs(cnt - 1)) return true;
    
            row[x] += 1 << t;
            col[y] += 1 << t;
            cell[x / 3][y / 3] += 1 << t;
            str[x * 9 + y] = '.';
    
        }
    
        return false;
    }
    
    int main()
    {
        for(int i = 0; i < N; i++) mp[1 << i] = i;
        for(int i = 0; i < 1 << N; i++)
        {
            int s = 0;
            for(int j = i; j; j -= lowbit(j)) s++;
            ones[i] = s; //i的二进制数中1的个数
        }
        
        while(cin >> str && str != "end")
        {
            init(); //预处理三个数组
            int cnt = 0; //表示要填多少个数字
            for(int i = 0, k = 0; i < N; i++)
                for(int j = 0; j < N; j++, k++)
                if(str[k] != '.')
                {
                    int t = str[k] - '1'; //数字从0 - 8
                    row[i] -= 1 << t; //将二进制数的第t位变成0
                    col[j] -= 1 << t;
                    cell[i/3][j/3] -= 1 << t;
                }
                else cnt ++;
            dfs(cnt);
            cout << str << endl;
        }
    
        return 0;
    }
    
    
    /*
    row[i]
    col[j]
    cell[i/3][j/3]
    爆搜的过程:
    1.选择一个未填数字的格子,该格子能填的数字个数是最少的
        每个点,行列九宫格数字的个数
        填数字
    
    2.枚举格子可以填的数字
    lowbit  以及 映射数组快速得到
    
    3.dfs下个
    
    4.....8.5
    .3.......
    ...7.....
    .2.....6.
    ....8.4..
    ....1....
    ...6.3.7.
    5..2.....
    1.4......
    
    优化搜索顺序 ok
    排除冗余信息
    可行性剪枝
    最优性剪枝
    */
    
    
    
    
    
    • 1

    信息

    ID
    100
    时间
    1000ms
    内存
    256MiB
    难度
    7
    标签
    递交数
    30
    已通过
    8
    上传者