• 深搜+剪枝--poj2676--数独


     题干描述  就是一个数独问题

    这道题说是简单题,但是我觉得这个“简单”是在对数据结构,递归非常熟悉的基础上,对于我这种新手其实并不简单,也有很多坑等我我去踩

    这道题说是剪枝,但是我觉得主要妙点还是好在gw老师的设置的数据结构太好了。见代码。

    当要在一个空格子(0)放数字时,直接放那些在这个空格子所在行、列、3*3小方框没出现过的数字,这样效率不就高了许多吗?

    但是,找到这些已经出现过的数字呢?记录下来?或者搜索一下?dwd

    gw老师的办法很棒,这里面有一个重要的启发是:当题目要频繁查找某个位置的元素的状态,例如本题中我们要频繁的查找某位置其所在行、列、3*3小方框是否包含某数字,这时就可以用位置做数组下标,用值记录状态(0,1),这样直接访问数组就获得了所需信息,不必查找。

    从这一题我认识到,我对递归的过程仍然不熟悉,特别是回溯,但是不能浮躁,不能气馁,慢慢来~

    ac代码:

    #include <cstring>
    #include <iostream>
    #include <vector>
    using namespace std;
    #define maxn 102
    
    int hn[10][10];  //记录,某行中是否存有某个数 
    int ln[10][10];
    int gn[10][10];
    
    int map[10][10];  //地图 
    
    struct pos{
        int r,c;
        pos(int rr,int cc):r(rr),c(cc){}
    };
    
    vector<pos> b;
    
    inline int gb(int r,int c){       //由行列号得到序号(1~81) 
        int rr=r/3;
        int cc=c/3;
        return rr*3+cc;
    }
    
    void saf(int i,int j,int num,int f){      //第f=1-->i行j列有num这个数,f=0意思相反 
        hn[i][num]=f;
        ln[j][num]=f;
        gn[gb(i,j)][num]=f;
    }
    
    bool isk(int i,int j,int num){            //num这个数放在i,j位置ok吗? 
        return !gn[gb(i,j)][num] && !hn[i][num]  && !ln[j][num]; 
    }
    
    int dfs(int n){
        if(n<0) return 1;               //从80->0 当n=-1代表前面0-80全部处理过 
        int r=b[n].r;
        int c=b[n].c;
        for(int i=1;i<=9;++i){
            if(isk(r,c,i)){
                map[r][c]=i;
                saf(r,c,i,1);
                if(dfs(n-1))
                return 1;
                else
                saf(r,c,i,0);           //回溯 
            }
        }
        return 0;
    }
    
    int main()
    {
        freopen("in.txt","r",stdin);
        int t;
        cin>>t;
        while(t--){
            memset(hn,0,sizeof(hn));
            memset(ln,0,sizeof(ln));
            memset(gn,0,sizeof(gn));
            b.clear();
            for(int i=0;i<9;i++)
            for(int j=0;j<9;j++){
                char c;
                cin>>c;
                map[i][j]=c-'0';
                if(map[i][j])
                saf(i,j,map[i][j],1);
                else
                b.push_back(pos(i,j));
            }
            if(dfs(b.size()-1)){
                for(int i=0;i<9;i++){
                    for(int j=0;j<9;j++)
                    cout<<char(map[i][j]+'0');
                    cout<<endl;
                }
            }    
        }
        return 0;
    }
    柳暗花明又一村
  • 相关阅读:
    AntItemInventoryScene道具栏列表显示
    AntItemBaseScene的功能分析
    杀掉一直处于 正在终止 状态的并发请求
    oracle文件版本
    某个系统配置文件 用户层的SQL
    系统配置SQL profile
    (转)oracle 查看表所占用的空间大小
    Workflow Mailer Notifications设置
    System Hold, Fix Manager before resetting counters
    Linux mail 命令参数
  • 原文地址:https://www.cnblogs.com/ucandoit/p/8530303.html
Copyright © 2020-2023  润新知