相当坑爹的一道题,也是NOIP2009年最后一题,相信难度已不必多说,而且也是唯一一道时限2s的题目。
网上有人用Dancing Links做此题,那就只能ORZ......
数独问题,是已经被证明了的NP完全问题,但是由于NOIP不可能因为Dancing Links去卡数据,所以较为优秀的方法应该是启发式搜索(亦或可以说是A*)
整体上的思路是,定义两个数组
int line[10],row[10] 代表每行每列剩余可填的数的个数
然后分别从小到大排序,确定一个搜索顺序——优先选择可填数少的地方(这个没争议吧,也不需要解释,平常用人脑玩数独时都是这个思路),即可dfs。
下面上代码吧(不易看清的地方都用了注释):
#include <iostream>
#include <cstdlib>
#include <cmath>
#include <algorithm>
using namespace std;
struct RestBlankWithId
{
int x,id; //x is the sum of rest blank , id is this line(or row)'s origin number
bool operator<(const RestBlankWithId comp_obj)const
{
return x>comp_obj.x;
}
};
int a[10][10],m[10][10],ans=-1;
bool x[10][10],y[10][10],n[10][10];
// if point (x,y) in it's line , row or the sudoku it belongs to
RestBlankWithId row[10],line[10];
// make the sum of rest blank in order , keep it's id , make sure which best A* order it will be
int order[81][2],tot_order=1; //best A* order in record
void A_star()
{
for(int i=1;i<=9;i++)
row[i].id=line[i].id=i;
sort(row+1,row+10);
sort(line+1,line+10);
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
if(!a[line[i].id][row[j].id])
{
order[tot_order][0]=line[i].id;
order[tot_order++][1]=row[j].id;
}
}
int belong(int i,int j) //jugde which sudoku this point belongs to
{
int xt = 0,yt = 0;
for(int k=6;k>=0;k-=3)
if(i-k>0)
{
xt=(k+3)/3;
break;
}
for(int k=6;k>=0;k-=3)
if(j-k>0)
{
yt=(k+3)/3;
break;
}
return yt+(xt-1)*3;
}
void init()
{
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
{
m[i][j]=10-max(abs(i-5),abs(j-5)); //each point mark
x[i][j]=y[i][j]=n[i][j]=true;
}
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
{
cin>>a[i][j];
if(a[i][j])
{
line[i].x++;
row[j].x++;
}
x[i][a[i][j]]=false;
y[j][a[i][j]]=false;
n[belong(i,j)][a[i][j]]=false;
}
}
void score()
{
int sum=0;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
sum+=m[i][j]*a[i][j];
ans=max(sum,ans);
}
void dfs(int step)
{
if(step==tot_order)
score();
else
for(int k=1;k<=9;k++)
{
int px=order[step][0],py=order[step][1];
if(n[belong(px,py)][k]&&x[px][k]&&y[py][k])
{ //number k must not appeal in same line , row or it's sudoku
a[px][py]=k; //try to push k in Map[px,py]
n[belong(px,py)][k]=x[px][k]=y[py][k]=false; //pre deal before dfs
dfs(step+1);
n[belong(px,py)][k]=x[px][k]=y[py][k]=true; //recover
}
}
}
int main()
{
init();
A_star();
dfs(1);
cout<<ans;
return 0;
}
最后再扯一句,至此,终于有一年的NOIP能AK了!