爆搜加优化!
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int s[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};//每个九宫格的预处理。
const int p[10][10]={0,0,0,0,0,0,0,0,0,0,
0,6,6,6,6,6,6,6,6,6,
0,6,7,7,7,7,7,7,7,6,
0,6,7,8,8,8,8,8,7,6,
0,6,7,8,9,9,9,8,7,6,
0,6,7,8,9,10,9,8,7,6,
0,6,7,8,9,9,9,8,7,6,
0,6,7,8,8,8,8,8,7,6,
0,6,7,7,7,7,7,7,7,6,
0,6,6,6,6,6,6,6,6,6};//分值。
bool line[10][10],row[10][10],ss[10][10],c[10][10];
int xx,yy,n,num,i,j,ans,k,m,now,last,cnt,a[10][10],f[10][10];//f是限制数组。
struct dong
{
int x,y;
}d[100];//d为枚举顺序。
inline void zbj(int i,int j)//找到i,j九宫格的左上角。笨方法!!
{
if(i<=3) xx=1;
else
{
if(i<=6) xx=4;
else xx=7;
}
if(j<=3) yy=1;
else
{
if(j<=6) yy=4;
else yy=7;
}
}
inline void nyh(int k)//寻找第k多0的位置。
{
int max=0,x,y,i,j;
for(i=1;i<=9;i++)
for(j=1;j<=9;j++)
if(c[i][j]&&f[i][j]>max)
{
max=f[i][j];
x=i;
y=j;
}
d[k].x=x;
d[k].y=y;
for(i=1;i<=9;i++)
{
f[i][y]++;
f[x][i]++;
}
zbj(x,y);
for(i=xx;i<=xx+2;i++)//同main中的预处理。
for(j=yy;j<=yy+2;j++)
f[i][j]++;
c[x][y]=false;
}
void lyd(int k)//dfs
{
if(k==num+1)//边界。
{
if(now>ans) ans=now;
return;
}
int x=d[k].x;int y=d[k].y;
for(int i=1;i<=9;i++)
if(line[x][i]&&row[y][i]&&ss[s[x][y]][i])
{
now+=i*p[x][y];
line[x][i]=false;
row[y][i]=false;
ss[s[x][y]][i]=false;
lyd(k+1);//递归!
now-=i*p[x][y];//以下为回溯。
line[x][i]=true;
row[y][i]=true;
ss[s[x][y]][i]=true;
}
}
int main()
{
memset(line,1,sizeof(line));//line标记列。
memset(row,1,sizeof(row));//row标记行
memset(ss,1,sizeof(ss));//ss预处理该九宫格。
for(i=1;i<=9;i++)
for(j=1;j<=9;j++)
{
scanf("%ld",&a[i][j]);
if(a[i][j]>0)
{
line[i][a[i][j]]=false;
row[j][a[i][j]]=false;
ss[s[i][j]][a[i][j]]=false;
last+=a[i][j]*p[i][j];//以上是对已有的分值进行预处理。
for(k=1;k<=9;k++)
{
f[i][k]++;
f[k][j]++;
}
zbj(i,j);
for(k=xx;k<=xx+2;k++)
for(m=yy;m<=yy+2;m++)
f[k][m]++;
}
else
{
num++;
c[i][j]=true;
}
}
for(i=1;i<=num;i++) nyh(i);//对于没有处理的数,从简单的(多0的)先来填补,附加上数独的规则即可。
ans=-1;
lyd(1);
if(ans==-1) last=0;
printf("%ld\n",ans+last);
return 0;
}
先说题,裸搜谁都会,但是至于优化,其实我也说不出来,我的不同在于使用了一个f数组来限制我的dfs,从而使时间缩短,不过具体这个f我也用的迷迷糊糊的,只能说是运气好,蒙对了,其他的就没什么可说的了,比赛时我自诩也打不出这样的代码,还是裸搜的性价比更高一些,也能拿到比较实惠的分数。
这道题同学都说很难,但我不觉的,可能是因为运气吧,但是我觉得有以下几点:①dfs我已经有一段时间没有再练过了,再看到一个dfs的题,之前在脑海里关于dfs的沉淀与大脑有了不错的磨合,所以做起来比较顺畅②我之前看过这道题,不过没有去写,只是偶尔的想想,比起那些非要在一天什么都不干也要A掉这道题的同学强,或许是当局者迷吧,再一看到这道题,以前的思路就源源不断的涌现出来了,所以,我认识到,平时的思考是非常重要的,它会在意想不到的地方带来意想不到的惊喜!
好了,这道题就到这里吧!