数独【DFS、二进制表示】

数独是一种传统益智游戏,你需要把一个9 × 9的数独补充完整,使得图中每行、每列、每个3 × 3的九宫格内数字1~9均恰好出现一次。

请编写一个程序填写数独。

数独.png
输入格式

输入包含多组测试用例。

每个测试用例占一行,包含81个字符,代表数独的81个格内数据(顺序总体由上到下,同行由左到右)。

每个字符都是一个数字(1-9)或一个”.”(表示尚未填充)。

您可以假设输入中的每个谜题都只有一个解决方案。

文件结尾处为包含单词“end”的单行,表示输入结束。
输出格式

每个测试用例,输出一行数据,代表填充完全后的数独。
输入样例:

.2738…1…1…6735…293.5692.8…6.1745.364…9518…7…8…6534…52…8.4…3…9…5.1…6…2…7…3…6…1…7.4…3.
end

输出样例:

527389416819426735436751829375692184194538267268174593643217958951843672782965341
416837529982465371735129468571298643293746185864351297647913852359682714128574936

链接:https://www.acwing.com/problem/content/description/168/

题解: DFS、用row、col、cell 三个数组,分别表示每行每列每个九宫格中可放的数字。 利用的是二进制的存储方式:
000000001 ->1 000000010 -》2 ,即看二进制中1在哪一位上,就表示那一位的映射的1、2、3…是可选的。
所以 每个格子可放的就是row、col、cell三个数字的交集(由交集也可想到用&即利用二进制)。

优化DFS:剪枝、记忆化、优化搜索顺序(优先搜索决策少的枚举量)

本题中使用了剪枝、优化搜索顺序技巧,每次搜索都是先从所有格子中选择出可选数最少的格子进行搜索。

#include <iostream>
using namespace std;

const int N=9;
int row[N],col[N],cell[N/3][N/3];
int hashtable[1 << N];//1-9的对应二进制数;
//优化搜索顺序,优先选择决策少的格子进行dfs
int ones[1 << N]; //记录二进制数对应的可选状态数
char str[100];

inline int lowbit(int j){
    return j&-j;
}

void init(){
    //对row、col、cell进行初始化
    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;
        }
    }
}

inline 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 mx,my;
    for(int i=0;i<N;i++)
    {
        for(int j=0;j<N;j++)
        {
            if(str[i*N+j]=='.')
            {
                if(ones[get(i,j)] < minv)
                {
                    minv=ones[get(i,j)];
                    mx=i;
                    my=j;
                }
            }
        }
    }//找出了先要修改的mx,my位置
    
    for(int i=get(mx,my);i>0;i-=lowbit(i))
    {
        //
        int t=hashtable[lowbit(i)];
        row[mx]-=1 << t-1;
        col[my]-=1 << t-1;
        cell[mx/3][my/3]-=1 << t-1;
        str[mx*N+my]='0'+t;
        if(dfs(cnt-1)==true) return true;
        row[mx]+=1 << t-1;
        col[my]+=1 << t-1;
        cell[mx/3][my/3]+=1 << t-1;
        str[mx*N+my]='.';
    }
    return false;
}

int main(){
    for(int i = 0 ;i < N ;i++)   hashtable[1<<i]=i+1; // 1-> 1 10-> 2...
    for(int i=0;i<1<<N;i++)
    {
        int s=0;
        for(int j=i;j>0;j-=lowbit(j))  s++;
        ones[i]=s;
    }
    
    while(cin >> str,str[0]!='e')
    {
        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]-'0';
                    row[i]-=1<<(t-1);
                    col[j]-=1<<(t-1);
                    cell[i/3][j/3]-=1<<(t-1);
                }
                else
                cnt++;
            }
        }
        dfs(cnt); //cnt表示有多少格子要填;
        cout << str << endl;
    }
    
    return 0;
}
发布了13 篇原创文章 · 获赞 0 · 访问量 163

猜你喜欢

转载自blog.csdn.net/qq_43964401/article/details/105464211