这道题。。重点是数独的性质
(原谅我第一次做没注意)
数独:每个区间,每行,每列数字都不能重复
然后。。为了方便计算,先打三个表:
#include<bits/stdc++.h>
using namespace std;
struct node { int l,r;}b[20]={};//这个。。好像没什么用,最开始加的。。后来发现用不上
int a[20][20]={},d[20][20]={}//这个点上的分值,
c[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};//这个点属于哪一个区间
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
{
scanf("%d",&a[i][j]);
if (i==5&&j==5)
{ d[i][j]=10; continue; }
if (i>=4&&j>=4&&i<=6&&j<=6)
{ d[i][j]=9; continue; }
if (i>=3&&j>=3&&i<=7&&j<=7)
{ d[i][j]=8; continue; }
if (i>=2&&j>=2&&i<=8&&j<=8)
{ d[i][j]=7; continue; }
d[i][j]=6;
}
b[1].l=b[2].l=b[3].l=1;
b[1].r=b[4].r=b[7].r=1;
b[4].l=b[5].l=b[6].l=4;
b[2].r=b[5].r=b[8].r=4;
b[7].l=b[8].l=b[9].l=7;
b[3].r=b[6].r=b[9].r=7;
接着来三个标记数组:
bool visg[20][20]={}//每个区间,visx[20][20]={}//每行,visy[20][20]={}//每列;
因为输入会有给定的值,所以先处理一遍:
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
if (a[i][j]!=0)
{
visg[c[i][j]][a[i][j]]=false;
visx[i][a[i][j]]=false;
visy[j][a[i][j]]=false;
}
}
}
这个搜索就很有趣了:
inline int ask(){
int k=0;
for(int i=1;i<=9;i++)
for(int j=1;j<=9;j++)
k+=a[i][j]*d[i][j];
return k;
}
inline void find(int x,int y){
if (x==10) //边界
{
ans=max(ans,ask());
return ;//这个return千万不要忘(最开始忘了。。然后。。停不下来,最后RE)
}
int st[100]={},t=0;
if (a[x][y]==0)//需要填数
{
for(int i=1;i<=9;i++)
if (visg[c[x][y]][i]&&visx[x][i]&&visy[y][i])//注意是都满足才能用(最开始满足一个用,还查了半天错)
st[++t]=i; //找能填的数
for(int i=1;i<=t;i++)
{
a[x][y]=st[i];
visg[c[x][y]][st[i]]=false;
visx[x][st[i]]=false;
visy[y][st[i]]=false;
if (y==9) find(x+1,1);//换行处理
else find(x,y+1);
a[x][y]=0;//最开始偷懒这句没加,想着下次循环会覆盖的。。然而。。
visg[c[x][y]][st[i]]=true; visx[x][st[i]]=true; visy[y][st[i]]=true;
} //回溯
}
else //不需要填数
if (y==9) find(x+1,1); else find(x,y+1);}
调用并输出:
find(1,1);
if (ans!=0) printf("%d",ans);//数独有解
else printf("-1");//数独无解
memset(visg,true,sizeof(visg));
memset(visx,true,sizeof(visx));
memset(visy,true,sizeof(visy));//这些初始值自然是不能忘的
总结:
这种大搜索第一注意边界,第二注意初值,第三能加的剪枝尽量加(虽然这道题没什么剪枝)
ps:回溯时前往不要偷懒。。不然死的很惨