【NOIP 2009 提高组】靶形数独


做题的时候看到这道题就直接放弃了,毕竟现实生活中的我就不怎么会填数独。

再一次觉得洛谷题解的强大。

简单易懂

#include<iostream>
#include<cstdio> 
using namespace std;
int MAP[10][10]= {
0,0,0,0,0,0,0,0,0,0,
0,1,1,1,2,2,2,3,3,3,
0,1,1,1,2,2,2,3,3,3,
0,1,1,1,2,2,2,3,3,3,
0,4,4,4,5,5,5,6,6,6,
0,4,4,4,5,5,5,6,6,6,
0,4,4,4,5,5,5,6,6,6,
0,7,7,7,8,8,8,9,9,9,
0,7,7,7,8,8,8,9,9,9,
0,7,7,7,8,8,8,9,9,9
  };
 int q[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 fangzheng[10][10];
bool x[10][10];//行,x[i][j]表示第几行的用了哪个数 
bool y[10][10];//列,y[i][j]表示第几列用了哪个数 
bool cube[10][10];//宫,哪个宫中的哪个数被用了 
int ans=0;
int  t1=0,t2=0;
int sum() ///当前生成数独的权值和
{
    int tmp=0;
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++)
        {
            tmp+=fangzheng[i][j]*q[i][j];
        }
    return tmp;
}
void dfs1(int i,int j) ///从右下角开始
{
    if(fangzheng[i][j]) ///已经填数了
    {
        if(i==1 && j==1)//已经是最后一个空了
        {
            ans=max(ans,sum());//对当前的权值和最佳解进行比对
            return;
        } 
        else//如果没有到
        {
            if(j==1) dfs1(i-1,9);//如果找到当前这一行的最后一个空
            else dfs1(i,j-1); ///不是就继续搜下一个
        }
    }
    else ///如果没填数
    {
        for(int k=1;k<=9;k++) ///填个数 
        if(!x[i][k] && !y[j][k] && !cube[MAP[i][j]][k])//如果这个数在当前的宫,行,列都没有填过
        {
            fangzheng[i][j]=k;//不妨试一试
            x[i][k]=true;//将行,列,宫标记为用过
            y[j][k]=true;
            cube[MAP[i][j]][k]=true;
            if(j-1<1)//如果是当行的最后一个
            {
                if(i-1<1) ///如果已经是(1,1)
                {
                    ans=max(ans,sum());
                    fangzheng[i][j]=0;
                    x[i][k]=false;
                    y[j][k]=false;
                    cube[MAP[i][j]][k]=false;
                    return;//算一下,随便再复原
                }
                else dfs1(i-1,9);//不是就继续找下一行
            }
            else dfs1(i,j-1);//不是就找下一个
            fangzheng[i][j]=0;//复原,方便下一次
            x[i][k]=false;
            y[j][k]=false;
            cube[MAP[i][j]][k]=false;
        }
    }
}
void dfs_2(int i,int j)//从左上向右下,差不多
{
    if(fangzheng[i][j])
    {
        if(i==9 && j==9)
        {
            ans=max(ans,sum());
            return;
        }
        else
        {
            if(j==9) dfs_2(i+1,1);
            else dfs_2(i,j+1);
        }
    }
    else
    {
        for(int k=1;k<=9;k++)
        if(!x[i][k] && !y[j][k] && !cube[MAP[i][j]][k])
        {
            fangzheng[i][j]=k;
            x[i][k]=true;
            y[j][k]=true;
            cube[MAP[i][j]][k]=true;
            if(j+1>9)
            {
                if(i+1>9)
                {
                   ans=max(ans,sum());
                    fangzheng[i][j]=0;
                    x[i][k]=false;
                    y[j][k]=false;
                    cube[MAP[i][j]][k]=false;
                    return;
                }
                else dfs_2(i+1,1);
            }
            else dfs_2(i,j+1);
            fangzheng[i][j]=0;
            x[i][k]=false;
            y[j][k]=false;
            cube[MAP[i][j]][k]=false;
        }
    }
}

int main()
{
    for(int i=1; i<=9; i++)
        for(int j=1; j<=9; j++)
        {
            cin>>fangzheng[i][j]; ///输入
            if(fangzheng[i][j])//如果是填好了的数,做好标记
            {
                x[i][fangzheng[i][j]]=true;
                y[j][fangzheng[i][j]]=true;
                cube[MAP[i][j]][fangzheng[i][j]]=true;
            }
            if (i+j<10 && fangzheng[i][j]==0) t1++; //左上的空
            if (i+j>10 && fangzheng[i][j]==0) t2++; //右上的空
        }
    if(t1>=t2) dfs1(9,9); //空格少就去哪边 
    else dfs_2(1,1);
    if(ans==0) cout<<"-1"; //没有最优解,就是搜不出来,无解
    else cout<<ans;
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_41734244/article/details/79781697
今日推荐