• 【题解】洛谷P1074 [NOIP2009TG] 靶形数独(DFS+剪枝)


    洛谷P1074:https://www.luogu.org/problemnew/show/P1074

    思路

    这道题一看就是DFS

    打一个分数表方便后面算分

    我用x y z数组分别表示行 列 宫 是否有放置数字

    用cnt结构体中no和zero分别表示每行行号每行的零的数量(下面会讲到为什么)

    我们把每行按照零的数量从小到大排序 并保留行号来计算(因为搜索的层数与每行0的个数有关)

    我们用一个队列q表示有几个点要枚举

    然后我们从零最少的那行开始枚举就ok了

    PS:ans一开始要赋值为-1 因为有无解的情况要输出-1(没有判无解的话95分 别问我咋知道的)

    代码

    #include<iostream>
    #include<algorithm>
    using namespace std;
    const int score[10][10]=
    {{0,0,0,0,0,0,0,0,0,0},
    {0,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}};
    int ans=-1,k,maxn;
    int map[10][10],q[1010][4];
    bool x[10][10],y[10][10],z[10][10];
    struct date
    {
        int no;
        int zero;
    }cnt[10];
    bool cmp(date a,date b)
    {
        return a.zero<b.zero;
    }
    int g(int ii,int jj)//判断宫 
    {
        if(ii<=3)
        {
            if(jj<=3) return 1;
            else if(jj<=6) return 2;
            else return 3;
        }
        else if(ii<=6)
        {
            if(jj<=3) return 4;
            else if(jj<=6) return 5;
            else return 6;
        }
        else
        {
            if(jj<=3) return 7;
            else if(jj<=6) return 8;
            else return 9;
        }
    }
    void cinn()
    {
        for(int i=1;i<=9;i++)
        {
            cnt[i].no=i;//记录行号 
            for(int j=1;j<=9;j++)
            {
                cin>>map[i][j];
                if(map[i][j]!=0)
                {
                    maxn+=map[i][j]*score[i][j];//预算本来就有的分数 
                    x[i][map[i][j]]=1; 
                    y[j][map[i][j]]=1;
                    z[g(i,j)][map[i][j]]=1;//把行列宫记录 
                }
                else
                cnt[i].zero++;//计算0的个数 
            }
        }
    }
    void dfs(int now,int sum)//now为队列中第几个点 sum为总分 
    {
        if(now>k)//如果队列中的每个点都被枚举过了 
        {
            ans=max(sum,ans);//找出最大值 
            return;
        }
        for(int i=1;i<=9;i++)//枚举数字 
            if(!x[q[now][1]][i]&&!y[q[now][2]][i]&&!z[q[now][3]][i])//如果行列宫均没有用过这个数字 
            {
                x[q[now][1]][i]=y[q[now][2]][i]=z[q[now][3]][i]=1;//行列宫记录 
                map[q[now][1]][q[now][2]]=i;//记录这个数字 
                dfs(now+1,sum+score[q[now][1]][q[now][2]]*map[q[now][1]][q[now][2]]);
                x[q[now][1]][i]=y[q[now][2]][i]=z[q[now][3]][i]=0;//还原操作 
                map[q[now][1]][q[now][2]]=0;
            }
    }
    int main()
    {
        cinn();
        sort(1+cnt,1+9+cnt,cmp);//排序 
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
            {
                if(!map[cnt[i].no][j])
                {
                    q[++k][1]=cnt[i].no;
                    q[k][2]=j;
                    q[k][3]=g(cnt[i].no,j);
                }
            }
        dfs(1,maxn);
        cout<<ans;
    }
    View Code
  • 相关阅读:
    安装Hadoop
    爬取全部的校园新闻
    理解爬虫原理
    复合数据类型,英文词频统计
    字符串操作、文件操作,英文词频统计预处理
    了解大数据的特点、来源与数据呈现方式
    四则运算升级
    初级四则运算
    分布式版本控制系统Git的安装与使用
    作业——12 hadoop大作业
  • 原文地址:https://www.cnblogs.com/BrokenString/p/9726490.html
Copyright © 2020-2023  润新知