zoukankan      html  css  js  c++  java
  • P1074 靶形数独

    传送门

    刚开始想都没想直接爆搜

    然后35

    然后试了优先找分值大的点,优先填大的数

    发现样例2都过不了

    放弃了

    考虑怎么剪枝

    对于一个点,有多种可能的数

    如果可能的数少,那么从这个点下去的分支也会比较少

    所以预处理一波

    把可以填的点按可以填的数的数量排序一遍

    然后按排序后的顺序dfs

    然后80...

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int mul[17][17],cnt,ans=-1,sum,mp[17][17];//mul为分值,mp为初始状态
    bool hor[17][17],ver[17][17],blk[17][17];//分别存每个行,列和宫可以放的数
    struct node
    {
        int x,y,num;
        bool pd[17];
        node() {memset(pd,0,sizeof(pd)); x=y=num=0; }
    }t[107];//存可以放的点
    inline bool cmp(const node a,const node b){return a.num<b.num; }
    //按可能的数的数量从小到大排序
    inline void dfs(int x,int y,int now,int stp)
    {
        //cout<<x<<" "<<y<<" "<<mul[x][y]<<"!";
        if(stp>cnt)
        {
            ans=max(ans,now+sum);
            return;
        }//如果放满就尝试更新答案
        int xx=(x-1)/3,yy=(y-1)/3,z=xx*3+yy+1;
        for(int k=9;k;k--)
        {
            if(hor[x][k]||ver[y][k]||blk[z][k]) continue;//判断重复
            hor[x][k]=ver[y][k]=blk[z][k]=1;
            //更新标记
            dfs(t[stp+1].x,t[stp+1].y,now+mul[x][y]*k,stp+1);//向下一层搜索
            hor[x][k]=ver[y][k]=blk[z][k]=0;
            //清除标记
        }
    }
    int main()
    {
        int a;
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
            {
                a=max(abs(5-i),abs(5-j));
                mul[i][j]=10-a;
            }//预处理分值
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
            {
                scanf("%d",&a);
                sum+=mul[i][j]*a;
                mp[i][j]=a;
                if(!a) continue;
                int x=(i-1)/3,y=(j-1)/3;
                if(hor[i][a]||ver[j][a]||blk[x*3+y+1][a])
                {
                    cout<<-1;
                    return 0;
                }//判断冲突
                hor[i][a]=1;
                ver[j][a]=1;
                blk[x*3+y+1][a]=1;
            }
        }//预处理行,列和宫的情况
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
            {
                if(mp[i][j]) continue;
                t[++cnt].x=i; t[cnt].y=j;
                for(int k=1;k<=9;k++)
                {
                    int x=(i-1)/3,y=(j-1)/3;
                    if(hor[i][k]||hor[j][k]||blk[x*3+y+1][k]) t[cnt].pd[k]=1;
                }
                for(int k=1;k<=9;k++)
                    if(!t[cnt].pd[k]) t[cnt].num++;
            }//预处理每个点的可以放的数的数量
        sort(t+1,t+cnt+1,cmp);//排序
        dfs(t[1].x,t[1].y,0,1);//按排序后的顺序dfs
        cout<<ans;
        return 0;
    }
    80分代码

    不会了...

    还能怎么剪枝啊!

    根本想不到了好吧

    然后就去看了看题解

    发现题解只按每一行的可能的数来剪枝...

    然后我就懵逼了..

    为什么我考虑行列和宫三种情况就TLE了

    题解只考虑行的情况能过...

    后来仔细想了想

    题解按行dfs,如果同一行前面已经放了,那么后面同一行的可能就会更少

    而我的是到处乱放,前面放完后比较不容易排除后面的可能

    应该是因为这个吧...

    反正这样能过,搜索大家都会

    然后要预处理一波

    看看就懂了,很简单的

    附上一个输出预处理结果的函数:

    inline void out()
    {
        cout<<"______"<<endl;
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
                cout<<mul[i][j]<<" ";
            cout<<endl;
        }
        cout<<"______"<<endl;
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
            {
                int x=(i-1)/3,y=(j-1)/3;
                cout<<x*3+y+1<<" ";
            }
            cout<<endl;
        }
        cout<<"______"<<endl;
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
                if(hor[i][j]) cout<<j<<" ";
            cout<<endl;
        }
        cout<<"______"<<endl;
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
                if(ver[i][j]) cout<<j<<" ";
            cout<<endl;
        }
        cout<<"______"<<endl;
        for(int i=1;i<=9;i++)
        {
            for(int j=1;j<=9;j++)
                if(blk[i][j]) cout<<j<<" ";
            cout<<endl;
        }
        cout<<"______"<<endl;
    }
    out

    然后是满分代码:

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<cmath>
    using namespace std;
    int mul[17][17],cnt,ans=-1,sum,mp[17][17];//mul为分值,mp为初始状态
    bool hor[17][17],ver[17][17],blk[17][17];//分别存每个行,列和宫可以放的数
    struct node
    {
        int x,y,num;
        bool pd[17];
        node() {memset(pd,0,sizeof(pd)); x=y=num=0; }
    }t[107];//存可以放的点
    struct data
    {
        int id,num;
        data() {id=num=0; }
    }d[17];//存每一行的可能
    inline bool cmp(const data a,const data b){return a.num<b.num; }//按每一行的可能排序
    inline void dfs(int x,int y,int now,int stp)
    {
        if(stp>cnt)
        {
            ans=max(ans,now+sum);
            return;
        }//如果放满就尝试更新答案
        int xx=(x-1)/3,yy=(y-1)/3,z=xx*3+yy+1;
        for(int k=9;k;k--)
        {
            if(hor[x][k]||ver[y][k]||blk[z][k]) continue;//判断重复
            hor[x][k]=ver[y][k]=blk[z][k]=1;
            //更新标记
            dfs(t[stp+1].x,t[stp+1].y,now+mul[x][y]*k,stp+1);//向下一层搜索
            hor[x][k]=ver[y][k]=blk[z][k]=0;
            //清除标记
        }
    }
    int main()
    {
        int a;
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
            {
                a=max(abs(5-i),abs(5-j));
                mul[i][j]=10-a;
            }//预处理分值
        for(int i=1;i<=9;i++)
        {
            d[i].id=i;//存一下行号,排序后就不会丢了
            for(int j=1;j<=9;j++)
            {
                scanf("%d",&a);
                sum+=mul[i][j]*a;//先更新一波初始分数
                mp[i][j]=a;
                if(!a) {d[i].num++; continue; }//如果是零就跳过
                int x=(i-1)/3,y=(j-1)/3;
                if(hor[i][a]||ver[j][a]||blk[x*3+y+1][a])
                {
                    cout<<-1;
                    return 0;
                }//判断冲突
                hor[i][a]=1;
                ver[j][a]=1;
                blk[x*3+y+1][a]=1;
                //预处理行列宫的情况
            }
        }
        sort(d+1,d+10,cmp);//按行排一波
        for(int i=1;i<=9;i++)
            for(int j=1;j<=9;j++)
                if(mp[d[i].id][j]==0)
                    t[++cnt].x=d[i].id,t[cnt].y=j;//把点按前面排的顺序加进来
        dfs(t[1].x,t[1].y,0,1);//按顺序搜下去
        cout<<ans;
        return 0;
    }
  • 相关阅读:
    spark的map和mapPartitions
    scala 语法速查
    spark 在yarn模式下提交作业
    spark的wordcount
    spark安装
    hadoop mapreduce求解有序TopN(高效模式)
    hadoop 自定义OutputFormat
    ONI无法启动: Uh oh! Unable to launch Neovim...
    Macbook外接显示器模糊解决方法
    macOS: sudo : Operation not permitted
  • 原文地址:https://www.cnblogs.com/LLTYYC/p/9612707.html
Copyright © 2011-2022 走看看