zoukankan      html  css  js  c++  java
  • 数独类型总结

    最近做完了洛谷的P1784 P1074,对数独类型的题目有所感触,现总结如下。

    往往数独类型的题目总是离不开DFS,从P1784说起,该题的要求是完成一个数独,先介绍一下数独的规则,在一个9*9的九宫格中,要求给初始空白格子填入数字(1~9),要求每一列、每一行、每一个3*3的小的九宫格都不能出现重复的数字。我们自然想到使用搜索解决此题,搜索的顺序是搜完一行搜下一行,即每次搜到第9个格子的时候跳转到下一行(这里用0~8循环),使用vx、vy、vk三个二维数组记录每一行、列、小九宫格中是否出现某数,并在搜索时进行回溯,其中需要注意的是如何判断当前的最小格是隶属于哪个小的3*3的九宫格的,我们通过尝试和思考发现对于用0~8表示行列的九宫格,我们用x表示行,用y表示列,那么我们vk[x/3*3+y/3][i]表示这个3*3小的九宫格是否出现了数字i,最后输出九宫格即可

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    int mp[10][10],vx[10][10],vy[10][10],vc[10][10];
    void dfs(int x,int y) {
        if(x==9) {
            for(int i=0; i<9; i++) {
                for(int j=0; j<9; j++) {
                    cout<<mp[i][j]<<" ";
                }
                cout<<endl;
            }
            return ;
        }
        if(y==9) {
            dfs(x+1,0);
            return ;
        }
        if(mp[x][y])
            dfs(x,y+1);
        else for(int i=1; i<=9; i++) {
            if(!vx[x][i] && !vy[y][i] && !vc[x/3*3+y/3][i]) {
                mp[x][y] =i;
                vx[x][i] =1;
                vy[y][i] =1;
                vc[x/3*3+y/3][i] =1;
                dfs(x,y+1);
                mp[x][y]=0;
                vx[x][i] =0;
                vy[y][i] =0;
                vc[x/3*3+y/3][i] =0;
            }
        }
    }
    int main() {
        for(int i=0; i<9; i++) {
            for(int j=0; j<9; j++){
                cin>>mp[i][j];
                vx[i][mp[i][j]]=1;
                vy[j][mp[i][j]]=1;
                vc[i/3*3+j/3][mp[i][j]]=1;
                
            }
        }
        dfs(0,0);
        return 0;
    }

    接下来我们做P1074靶向数独的时候就有了一定的基础了,该题只是在数独上做了一些延伸,即需要每一步记录分数,大体基本不变,只是添加一个分数的参数的话,并在搜索完成后比较最大值,注意如果没有结果,就直接输出-1,那我们不妨将ans一开始定义为-1,这样如果没有答案的话是无法进行最后一步的比较的,就直接输出-1,接下来我们需要打一个表(也可以不打表,但需要一种类似处理所在3*3九宫格位置的方法,留给读者思考),记录不同位置对应靶的分数,这样处理后提交发现T了几个点,我们就需要优化如何优化,似乎无法进行最优化和可行性剪枝。我们思考一下,是否现实中我们在做数独题的时候,我们总是先将数字最多的一个部分先填满,以便后续的推理,这里的优化思想就来源于这种思想,我们需要一个记录每一行元素个数的数组,它同时也要记忆当前的真实行数,并最后从大到小排序,我们从元素最多的一行开始搜索,这样就能完美解决这一问题了。

    代码如下:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int mp[10][10],vc[10][10],vr[10][10],vk[10][10],ans=-1;
    int biao[10][10]={
    {6,6,6,6,6,6,6,6,6,0},
    {6,7,7,7,7,7,7,7,6,0},
    {6,7,8,8,8,8,8,7,6,0},
    {6,7,8,9,9,9,8,7,6,0},
    {6,7,8,9,10,9,8,7,6,0},
    {6,7,8,9,9,9,8,7,6,0},
    {6,7,8,8,8,8,8,7,6,0},
    {6,7,7,7,7,7,7,7,6,0},
    {6,6,6,6,6,6,6,6,6,0},
    };
    struct node{
        int cnt,v;
        friend    bool operator <(const node& a,const node& b) {
            return a.cnt>b.cnt;
        }
    }s[10];
    void dfs(int x,int y,int sum){
        int temp = s[x].v;
        if(x==9) {
            ans = max(ans,sum);
            return ;
        }
        if(y==9){
            dfs(x+1,0,sum);
            return ;    
        }    
        if(mp[temp][y]) dfs(x,y+1,sum+biao[temp][y]*mp[temp][y]);    
        else for(int i=1; i<=9; i++) {
            if(!vc[temp][i]&&!vr[y][i]&&!vk[temp/3*3+y/3][i]) {
                vc[temp][i]=1;
                vr[y][i]=1;
                vk[temp/3*3+y/3][i]=1;
                mp[temp][y]=i;
                dfs(x,y+1,sum+biao[temp][y]*i);
                vc[temp][i]=0;
                vr[y][i]=0;
                vk[temp/3*3+y/3][i]=0;
                mp[temp][y]=0;
            }
        }
    }
    int main() {
        for(int i=0; i<9; i++) {
            s[i].v=i;
            for(int j=0; j<9; j++) {
                cin>>mp[i][j];
                vc[i][mp[i][j]]=1;
                vr[j][mp[i][j]]=1;
                vk[i/3*3+j/3][mp[i][j]]=1;
                if(mp[i][j]) s[i].cnt++;
            }
        }
        sort(s,s+9);
        dfs(0,0,0);
        cout<<ans;
        return 0;
    } 
  • 相关阅读:
    Java实现 LeetCode 455 分发饼干
    Java实现 LeetCode 455 分发饼干
    Java实现 LeetCode 455 分发饼干
    Java实现 LeetCode 454 四数相加 II
    Java实现 LeetCode 454 四数相加 II
    Java实现 LeetCode 454 四数相加 II
    FFmpeg解码H264及swscale缩放详解
    linux中cat more less head tail 命令区别
    C语言字符串操作总结大全(超详细)
    如何使用eclipse进行嵌入式Linux的开发
  • 原文地址:https://www.cnblogs.com/delta-cnc/p/12394464.html
Copyright © 2011-2022 走看看