codevs 1174 靶形数独 2009年NOIP全国联赛提高组

咳咳,经过一个星期断断续续的痛苦挣扎终于把这个数独题改好了~
/当然是在参考了无数网上代码以后/
作为纯正的蒟蒻怎么能像YWQ同学那样作死地选择那个酷似十滴水代码三百多行又臭又长的舞蹈链呢?聪明的我果断选择暴搜~
当然暴搜是有技巧的,应该搜的同时判断并及时剪枝。同时还有一个技巧,如果某一个格子横行纵行小九宫格都要满足的情况下能填入的数最少,那就从它开始填比较快。
最后代码90行秒杀哈哈哈

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ms(x,y) memset(x,y,sizeof(x));
#define inf 0x3fffffff 
using namespace std;
int shudu[10][10],n,ans=0;
bool F=false,H[10][10],L[10][10],A[10][10];
//H--行,L--列,A--小九宫格;H[i][j]=1,表示第i行能够填入数字j,其余以此类推。TRUE未填,FALSE已填
int At(int x,int y){
    return (x-1)/3*3+(y+2)/3;
}//确定(x,y)所在的小九宫格
int Abs(int a){
    return a<0?-a:a;
}
int Score(int x,int y)
{
    return 10-max(Abs(x-5),Abs(y-5));
}//计算(x,y)的分数  
void init(){
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++){
            scanf("%d",&shudu[i][j]);
            ans+=shudu[i][j]*Score(i,j);
        }
    for(int i=1;i<=9;i++)
    for(int j=1;j<=9;j++)
        if(shudu[i][j]){
            if(H[i][shudu[i][j]]&&L[j][shudu[i][j]]&&A[At(i,j)][shudu[i][j]])
                H[i][shudu[i][j]]=L[j][shudu[i][j]]=A[At(i,j)][shudu[i][j]]=false;  
            else{//如果读入的数已经自相矛盾可直接判无解
                F=true;
                printf("-1");
                return ;  
            }  
        }
}
void dfs(int marks){
    int minn=inf,px=0,py=0,goal=0,num,K;
    for(int i=1;i<=9;i++)
        for(int j=1;j<=9;j++)
            if(!shudu[i][j]){
                num=0;
                K=0;
                for(int k=1;k<=9;k++)
                    if(H[i][k]&&L[j][k]&&A[At(i,j)][k]){
                        num++;
                        K=k;
                    }
                goal+=K*Score(i,j);//估计最高得分.(K一定是能填进里面的数中最大的)
                if(num<minn){
                    minn=num;
                    px=i;
                    py=j;
                }//若已知量极多,则从此处开始填 
            }
    if(goal+marks<=ans)
        return ;//剪枝
    if(goal==0){
        F=true;// 填完了
        ans=max(ans,marks);
        return ;
    }
    if(num==0)
        return ;
    int at=At(px,py),score=Score(px,py);
    for(int i=1;i<=9;i++){
        if(H[px][i]&&L[py][i]&&A[at][i]){
            H[px][i]=L[py][i]=A[at][i]=false;
            shudu[px][py]=i;
            dfs(marks+i*score);//再来填下一个
            shudu[px][py]=0;
            H[px][i]=L[py][i]=A[at][i]=true;
        }
    }
    return ;
}
int main(){
    ms(H,true);
    ms(L,true);
    ms(A,true);//初始化全部都可以填 
    init();
    if(F)
        return 0;
    dfs(ans);
    if(F)
        printf("%d",ans);
    else printf("-1");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值