首先这题是NOIP2015提高组的最后一题,做出来的时候要上天了!感觉比较简(kun)单(nan)
下面就来讲一下我做这道题的过程
这道题的核心就是让你填数字。
规则有三点:
1、在3*3的小矩阵中不能出现重复的数字
2、一行也不能出现
3、一列也不能出现
70 points 做法
则我们定义三个数组,分别表示
第一个:small[i][j][k]表示第i行第j个数独k有没有出现过
第二个:hang[i][j]表示第i行第j个数有没有出现
第三个:lie[i][j]表示第i列第j个数有没有出现。
然后爆搜做法,记住每行填满了数就要换行。
100 points 做法
数组和上面一样,因为是暴力,我们要尽量减少我们爆搜的子状态来节省时间。
那么怎么节省呢?
我们不难发现,先从填数少的开始搜索最好,为什么呢?
理由:每次如果从填数多的开始枚举,那么每次的第一状态会产生更多的子状态,
反之,如果从填数少的枚举,那么每次的第一状态少,则会少去大量多余的子状态。
具体怎么实现呢?
我们可以排序,因此想到结构体,结构体的变量有两个。
1、当前的行数——xx
2、当前行0的个数——sl
我们以变量2来排序。
每次爆搜时,参数变成 now和y,x去掉
第x行改成子状态的xx节点即可。
那么每次多一行我们就多加一次now
最后分数用一个score数组存好,每次加上score[i-1][j-1],
因为我们打表是从0开始的,所以不要忘了减一,一开始犯了这个错误。
随后,记住判断如果ans=0时,证明无解,所以输出-1
代码如下:
//这道题的核心优化就是先从填的数字少开始找(也就是0多的开始找),这样会极大的减少子状态,从而从70到100
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct node
{
int sl,xx;
}ss[1100];
bool small[5][5][10];//small[i][j][k]表示第i行第j个数独k有没有出现过
bool hang[10][10];//hang[i][j]表示第i行第j个数有没有出现
bool lie[10][10];//lie[i][j]表示第i列第j个数有没有出现]
int a[10][10];
int maxx=0;
bool cmp(node n1,node n2)
{
return n1.sl<n2.sl;
}
int shudu[10][10]=
{
{6,6,6,6,6,6,6,6,6},
{6,7,7,7,7,7,7,7,6},
{6,7,8,8,8,8,8,7,6},
{6,7,8,9,9,9,8,7,6},
{6,7,8,9,10,9,8,7,6},
{6,7,8,9,9,9,8,7,6},
{6,7,8,8,8,8,8,7,6},
{6,7,7,7,7,7,7,7,6},
{6,6,6,6,6,6,6,6,6},
};
void dfs(int now,int y)
{
int x=ss[now].xx;
if(now==10)//填完就判断ans是多少
{
int ans=0;
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
ans=ans+a[i][j]*shudu[i-1][j-1];
}
}
maxx=max(maxx,ans);
return ;
}
if(a[x][y]!=0)
{
if(y==9) //一列填完填下一列
{
dfs(now+1,1);
}
else dfs(now,y+1);
}
else//填数字
{
for(int i=1;i<=9;i++)
{
if(lie[x][i]==false&&hang[y][i]==false&&small[(x-1)/3+1][(y-1)/3+1][i]==false)
{
a[x][y]=i;
lie[x][i]=true;hang[y][i]=true;small[(x-1)/3+1][(y-1)/3+1][i]=true;
if(y==9) dfs(now+1,1);
else dfs(now,y+1);
a[x][y]=0;
lie[x][i]=false;hang[y][i]=false;small[(x-1)/3+1][(y-1)/3+1][i]=false;
}
}
}
}
int main()
{
memset(hang,false,sizeof(hang));
memset(lie,false,sizeof(lie));
memset(small,false,sizeof(small));
for(int i=1;i<=9;i++)
{
ss[i].xx=i;
for(int j=1;j<=9;j++)
{
scanf("%d",&a[i][j]);
small[(i-1)/3+1][(j-1)/3+1][a[i][j]]=true;
lie[i][a[i][j]]=true;
hang[j][a[i][j]]=true;
if(a[i][j]==0) ss[i].sl++;
}
}
sort(ss+1,ss+10,cmp);
dfs(1,1);
if(maxx==0) printf("-1");
else printf("%d",maxx);
}
感谢FHM大佬的指导,如有不好的请指出
请经过博主允许方可转载,谢谢!!