• Acwing-169-数独2(搜索, 剪枝)


    链接:

    https://www.acwing.com/problem/content/171/

    题意:

    请你将一个16x16的数独填写完整,使得每行、每列、每个4x4十六宫格内字母A~P均恰好出现一次。

    保证每个输入只有唯一解决方案。

    思路:

    每个坐标维护一个16位的数, 用来记录某个值是否使用.
    对每个位置, 如果只能填一个,则直接填, 对空格如果不能填, 则返回.
    对每一行, 只能在一个位置使用的值直接填, 同时一行不能覆盖a-p,则返回,
    列, 块同理.
    再从所有可行位置,找到一个可填值最少的开始枚举.
    还要多开数组记录状态, 方便复原.

    代码:

    #include <bits/stdc++.h>
    using namespace std;
    
    const int N = 16;
    
    char Map[N][N+1];
    char TmpMap[N*N+1][N][N+1];
    int State[N][N];
    int TmpS1[N*N+1][N][N], TmpS2[N*N+1][N][N];
    int Num[1<<N], Cnt[1<<N];
    int cnt;
    int Lowbit(int x)
    {
        return x&(-x);
    }
    
    void Change(int x, int y, int p)
    {
        Map[x][y] = 'A'+p;
        for (int i = 0;i < N;i++)
        {
            State[x][i] &= ~(1<<p);
            State[i][y] &= ~(1<<p);
        }
        int sx = (x/4)*4, sy = (y/4)*4;
        for (int i = 0;i < 4;i++)
        {
            for (int j = 0;j < 4;j++)
                State[sx+i][sy+j] &= ~(1<<p);
        }
        State[x][y] = 1<<p;
    }
    bool Dfs(int step)
    {
        if (step == 0)
            return true;
        int tmpcnt = step;
        memcpy(TmpS1[tmpcnt], State, sizeof State);
        memcpy(TmpMap[tmpcnt], Map, sizeof Map);
        //保存副本
        //处理每个空格
        for (int i = 0;i < N;i++)
        {
            for (int j = 0;j < N;j++)
            {
                if (Map[i][j] == '-')
                {
                    if (State[i][j] == 0)
                    {
                        memcpy(State, TmpS1[tmpcnt], sizeof State);
                        memcpy(Map, TmpMap[tmpcnt], sizeof Map);
                        return false;
                    }
                    if (Cnt[State[i][j]] == 1)
                    {
                        Change(i, j, Num[State[i][j]]);
                        step--;
                    }
                }
            }
        }
        //处理每一行
        for (int i = 0;i < N;i++)
        {
            int all = 0, use = (1<<N)-1;
            int used = 0;
            for (int j = 0;j < N;j++)
            {
                int s = State[i][j];
                use &= ~(all & s);//记录只在一个位置出现过的点
                all |= s;//记录全集
                if (Map[i][j] != '-')
                    used |= State[i][j];//记录放置的点
            }
    
            if (all != (1<<N)-1)
            {
                memcpy(State, TmpS1[tmpcnt], sizeof State);
                memcpy(Map, TmpMap[tmpcnt], sizeof Map);
                return false;
            }
    
            for (int j = use;j > 0;j -= Lowbit(j))
            {
                int t = Lowbit(j);
                if (!(used & t))
                {
                    for (int k = 0;k < N;k++)
                    {
                        if (State[i][k] & t)
                        {
                            Change(i, k, Num[t]);
                            --step;
                            break;
                        }
                    }
                }
            }
        }
        //处理每一列
        for (int i = 0;i < N;i++)
        {
            int all = 0, use = (1<<N)-1;
            int used = 0;
            for (int j = 0;j < N;j++)
            {
                int s = State[j][i];
                use &= ~(all & s);
                all |= s;
                if (Map[j][i] != '-')
                    used |= State[j][i];
            }
    
            if (all != (1<<N)-1)
            {
                memcpy(State, TmpS1[tmpcnt], sizeof State);
                memcpy(Map, TmpMap[tmpcnt], sizeof Map);
                return false;
            }
    
            for (int j = use;j > 0;j -= Lowbit(j))
            {
                int t = Lowbit(j);
                if (!(used & t))
                {
                    for (int k = 0;k < N;k++)
                    {
                        if (State[k][i] & t)
                        {
                            Change(k, i, Num[t]);
                            --step;
                            break;
                        }
                    }
                }
            }
        }
        //处理每一个区块
        for (int i = 0;i < N;i++)
        {
            int all = 0, use = (1<<N)-1;
            int used = 0;
    
            for (int j = 0;j < N;j++)
            {
                int sx = i/4*4, sy = i%4*4;
                int dx = j/4, dy = j%4;
                int s = State[sx+dx][sy+dy];
                use &= ~(all & s);
                all |= s;
                if (Map[sx+dx][sy+dy] != '-')
                    used |= State[sx+dx][sy+dy];
            }
    
            if (all != (1<<N)-1)
            {
                memcpy(State, TmpS1[tmpcnt], sizeof State);
                memcpy(Map, TmpMap[tmpcnt], sizeof Map);
                return false;
            }
    
            for (int j = use;j > 0;j -= Lowbit(j))
            {
                int t = Lowbit(j);
                if (!(used & t))
                {
                    for (int k = 0;k < N;k++)
                    {
                        int sx = i/4*4, sy = i%4*4;
                        int dx = k/4, dy = k%4;
                        if (State[sx+dx][sy+dy] & t)
                        {
                            Change(sx+dx, sy+dy, Num[t]);
                            --step;
                            break;
                        }
                    }
                }
            }
        }
    
    //    cout << step << endl;
        if (step == 0)
            return true;
        int x, y, s = 100;
        for (int i = 0;i < N;i++)
        {
            for (int j = 0;j < N;j++)
            {
                if (Map[i][j] == '-' && Cnt[State[i][j]] < s)
                {
                    s = Cnt[State[i][j]];
                    x = i, y = j;
                }
            }
        }
    
    
        memcpy(TmpS2[tmpcnt], State, sizeof State);
        for (int i = State[x][y];i > 0;i -= Lowbit(i))
        {
            memcpy(State, TmpS2[tmpcnt], sizeof State);
            Change(x, y, Num[Lowbit(i)]);
            if (Dfs(step-1))
                return true;
        }
        memcpy(State, TmpS1[tmpcnt], sizeof State);
        memcpy(Map, TmpMap[tmpcnt], sizeof Map);
        return false;
    }
    
    int main()
    {
        for (int i = 0;i < N;i++)
            Num[1<<i] = i;
        for (int i = 0;i < (1<<N);i++)
        {
            for (int j = i;j > 0;j -= Lowbit(j))
                Cnt[i]++;
        }
        while (cin >> Map[0])
        {
            for (int i = 1;i < N;i++)
                cin >> Map[i];
            for (int i = 0;i < N;i++)
            {
                for (int j = 0;j < N;j++)
                    State[i][j] = (1<<N)-1;
            }
            cnt = 0;
            for (int i = 0;i < N;i++)
            {
                for (int j = 0;j < N;j++)
                {
                    if (Map[i][j] != '-')
                        Change(i, j, Map[i][j]-'A');
                    else
                        cnt++;
                }
            }
            Dfs(cnt);
            for (int i = 0;i < N;i++)
                puts(Map[i]);
            puts("");
        }
    
        return 0;
    }
    
  • 相关阅读:
    程序员的双11:3723亿,你贡献了几分力?
    程序员国企1周上班5小时?国企VS私企,应该如何选择?
    C++没有"垃圾回收"功能?智能指针,实现C++的内存管理
    【C++学习笔记】什么是C++STL?掌握C++ STL的核心很重要!
    都要2021年了,现代C++有什么值得我们学习的?
    解析:C++如何实现简单的学生管理系统(源码分享)
    程序员过高工资导致加班?应该降低程序员工资?网友:放过其他苦逼的程序员吧
    结对-结对编程项目作业名称-需求分析
    使用对话框模板创建一个InputBox()在C + +
    选择图标
  • 原文地址:https://www.cnblogs.com/YDDDD/p/11552600.html
Copyright © 2020-2023  润新知