可以用跳舞链,但由于我不会,就只有秀一秀深搜技术了。
数据结构:
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"; }