可以用跳舞链,但由于我不会,就只有秀一秀深搜技术了。
数据结构:
map[i][j]存的是填的数字;
row[x][i]表示x行i个数是否出现过;
file[x][i]表示x列i个数是否出现过;
f[x][y]返回x,y属于哪一个九宫格区域;
area[x][i] 表示第x个九宫格区域中i是否出现过。
vis[x]记录深搜的顺序;
score数组当然是得分表了。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
struct point {
int x,y;
}vis[90];
bool row[15][15],file[15][15],area[15][15];
int map[15][15],score[15][15],best=0,done=0,p=0,ok=0;
int f[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}};
bool find_best(int &x,int &y){ //找到当前可填的数最少的一格
int i,j,cur=9,cnt,k;
for(i=1;i<=9;i++)
for(j=1,cnt=0;j<=9;j++)
if(!map[i][j]){
for(k=1;k<=9;k++)
if(!row[i][k]&&!file[j][k]&&!area[f[i][j]][k])
cnt++; //计数
if(!cnt)return false; //不能填了
if(cnt<=cur)x=i,y=j,cur=cnt;
}
return true;
}
void search(int dep ,int cur){
int i,j,x=0,y=0;
if(vis[dep].x&&vis[dep].y)
x=vis[dep].x,y=vis[dep].y;
//如果已经知道该搜索哪一格,那就将计就计吧。
else if (!find_best(x,y)) return; //到这一步已经有个格子已经不可行了
else
vis[dep].x=x,vis[dep].y=y; //记下顺序
if(cur+(81-dep)*90<=best)return; //最优化仍然不如当前的答案
if(dep==81){ //已经填完
ok=1;
best=max(best,cur);
return ;
}
for(i=1;i<=9;i++)
if(!row[x][i]&&!file[y][i]&&!area[f[x][y]][i]){
map[x][y]=i;
row[x][i]=file[y][i]=area[f[x][y]][i]=true;
search(dep+1,cur+score[x][y]*i);
row[x][i]=file[y][i]=area[f[x][y]][i]=false;
map[x][y]=0;
}
}
void set_map(){
int i,k,j;
score[5][5]=10;
for(i=1;i<=9;i++)
for(k=1;k<=9;k++){
scanf("%d",&map[i][k]);
score[i][k]=score[5][5]-max(abs(i-5),abs(k-5));//计算每格的得分
j=map[i][k];
if(j){
done++;
row[i][j]=file[k][j]=area[f[i][k]][j]=true;
best+=j*score[i][k];
}
}
}
int main(){
set_map();
memset(vis,0,sizeof(vis));
search(done,best);
if(ok)cout<<best;
else cout<<"-1";
}