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

删除回忆录丶 提交于 2019-11-30 03:34:18

链接:

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;
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!