数独(深搜 剪枝)

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

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

输入格式
输入包含多组测试用例。

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

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

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

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

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

输入样例:
4.....8.5.3..........7......2.....6.....8.4......1.......6.3.7.5..2.....1.4......
......52..8.4......3...9...5.1...6..2..7........3.....6...1..........7.4.......3.
end
输出样例:
417369825632158947958724316825437169791586432346912758289643571573291684164875293
416837529982465371735129468571298643293746185864351297647913852359682714128574936

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 9;
char str[100];
int ones[1<<N],map[1<<N];
int col[N],row[N],cell[3][3];


void init()
{
    for(int i = 0; i < N; i++) col[i] = row[i] = (1 << N) -1;//每一行每一列都是1
    
    for(int i = 0; i < 3; i ++)
    {
        for(int j =0 ; j< 3; j ++)
        {
            cell[i][j] = (1<<N)-1;//初始化 每一个九宫格都是1
        }
    }
}

void draw(int x ,int y , int t , bool is_set)
{
    if(is_set)str[x*N +y] = t +'1';
    else str[x * N + y] = '.';
    
    int v = 1 << t;
    if(!is_set)    v = -v;
    
    row[x] -=v;
    col[y]-=v;
    cell[x/3][y/3] -= v;
    
}

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

int get(int x,int y)
{
    return col[y] & row[x] & cell[x/3][y/3];//& 計算出來能放数的位置
}

bool dfs(int cnt)
{
    if(!cnt) return true;
    int maxv = 10;
    int x, y;
    for(int i = 0; i < N ; i ++)
    {
        for(int j = 0; j < N ; j ++)
        {
            if(str[i * N + j] == '.')
            {
                int state = get(i,j);
                if(ones[state] < maxv)
                {
                      maxv = ones[state];
                     x = i , y = j ;
                   
                }
            }
        }
    }
    
    int state =get(x,y);
    
    for(int i = state; i ; i -= lowbit(i))
    {
        int t = map[lowbit(i)];
        draw(x,y,t,true);//把这个数放进去
        if(dfs(cnt - 1))return true;//如果能放进去
        draw(x,y,t,false);
    }
    return false;
    
}


int main()
{
    for(int i = 0; i < 1 <<N ; i ++)
    {   int cnt = 0;
       for(int j = 0;  j < N ;j ++)
       {
            if(i>> j & 1)cnt++;
       }
        ones[i] = cnt;//纪录每一个二进制数里1的个数
    }
    
    for(int i = 0; i < N ; i ++) map[1 << i] = i;//log 对应的 数是多少
    
    

    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] =='.')cnt++;//能放数的位置
                else
                {
                    int t = str[k]-'1';
                    draw(i,j,t,true);
                }
            }
        }
        dfs(cnt);
        puts(str);
    }
    return 0;
}


原文地址:https://www.cnblogs.com/wk-love-zsy/p/14169720.html