您的位置:首页 > 其它

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

2017-03-10 16:40 423 查看
咳咳,经过一个星期断断续续的痛苦挣扎终于把这个数独题改好了~

/当然是在参考了无数网上代码以后/

作为纯正的蒟蒻怎么能像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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  2009