zoukankan      html  css  js  c++  java
  • 数独(深搜 剪枝)

    数独是一种传统益智游戏,你需要把一个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;
    }
    
    
    
  • 相关阅读:
    Unit of Work
    OAuth做webapi认证
    Js数组
    UWP开发的一些思考
    表格行拖拽
    委托
    Git协作流程(转)
    全自动Web后门扫描(转)
    Gradle 2.0用户手册——总览(译)(转)
    面向对象之两大要领 (转)
  • 原文地址:https://www.cnblogs.com/wk-love-zsy/p/14169720.html
Copyright © 2011-2022 走看看