靶形数独

说好的一道位运算的题,结果二维数组好像就可以了。
我们在玩数独时,一般都会去选择一个“突破口”,通常我们会找到可填数字数目最少的那个方格,然后人脑进行判断。这里也一样,我们在搜索的时候就尽量选择那些比较“容易填”的方格先入手,具体就是找到可填数目最少的那个方格,然后搜索。这样就不需要任何其他优化能通过Noip的数据。

#include<cstdio>  
#include<cstring>  
#include<algorithm>  
#define N 10  

using namespace std;  

struct Node  
{  
    int x,y;  
};  

int getdist(int x,int y)  
{  
    return (x/3)*3+(y/3);  
}  
const int Index[N][N]=  
{  
{6,6,6,6,6,6,6,6,6},  
{6,7,7,7,7,7,7,7,6},  
{6,7,8,8,8,8,8,7,6},  
{6,7,8,9,9,9,8,7,6},  
{6,7,8,9,10,9,8,7,6},  
{6,7,8,9,9,9,8,7,6},  
{6,7,8,8,8,8,8,7,6},  
{6,7,7,7,7,7,7,7,6},  
{6,6,6,6,6,6,6,6,6}  
};  
bool line[N][N],list[N][N],dist[N][N];  
int data[N][N],tmp[N][N],Cnt,Ans;  

Node getnext()  
{  
    Node tmp;  
    int min,t;  
    tmp.x=N;  
    tmp.y=N;  
    min=N;  
    for (int i=0;i<9;i++)  
        for (int j=0;j<9;j++)   
            if (!data[i][j])  
            {  
                t=0;  
                for (int k=1;k<=9;k++)  
                    if (!line[i][k])  
                        if (!list[k][j])  
                            if (!dist[getdist(i,j)][k]) t++;  
                if (t<min)  
                {  
                    min=t;  
                    tmp.x=i;  
                    tmp.y=j;  
                }  
            }  
    return tmp;  
}  
int getans()  
{  
    int tmp;  
    tmp=0;  
    for (int i=0;i<9;i++)  
        for (int j=0;j<9;j++) tmp+=Index[i][j]*data[i][j];  
    return tmp;  
}  
void change(int x,int y,int k)  
{  
    data[x][y]^=k;  
    line[x][k]^=1;  
    list[k][y]^=1;  
    dist[getdist(x,y)][k]^=1;  
}  
void solve(int k)  
{  
    if (k>Cnt)  
    {  
        Ans=max(Ans,getans());  
        return;  
    }  
    Node tmp;  
    tmp=getnext();  
    if (tmp.x==N && tmp.y==N) return;  
    for (int i=1;i<=9;i++)  
        if (!line[tmp.x][i])  
            if (!list[i][tmp.y])  
                if (!dist[getdist(tmp.x,tmp.y)][i])  
                {  
//                  printf("At X:%d Y:%d,By %d,%d have been getten\n",tmp.x+1,tmp.y+1,i,k-1);  
                    change(tmp.x,tmp.y,i);  
                    solve(k+1);  
                    change(tmp.x,tmp.y,i);  
                }  
    return;  
}  

int main()  
{  
    memset(line,0,sizeof(line));  
    memset(list,0,sizeof(list));  
    memset(dist,0,sizeof(dist));  
    Cnt=(N-1)*(N-1);  
    for (int i=0;i<9;i++)   
        for (int j=0;j<9;j++)   
        {  
            scanf("%d",&data[i][j]);  
            if (data[i][j])  
            {  
                Cnt--;  
                line[i][data[i][j]]=true;  
                list[data[i][j]][j]=true;  
                dist[getdist(i,j)][data[i][j]]=true;  
            }  
        }  
    Ans=-1;  
    solve(1);  
    printf("%d\n",Ans);  
    return 0;  
}  
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值