最近做完了洛谷的P1784 P1074,对数独类型的题目有所感触,现总结如下。
往往数独类型的题目总是离不开DFS,从P1784说起,该题的要求是完成一个数独,先介绍一下数独的规则,在一个9*9的九宫格中,要求给初始空白格子填入数字(1~9),要求每一列、每一行、每一个3*3的小的九宫格都不能出现重复的数字。我们自然想到使用搜索解决此题,搜索的顺序是搜完一行搜下一行,即每次搜到第9个格子的时候跳转到下一行(这里用0~8循环),使用vx、vy、vk三个二维数组记录每一行、列、小九宫格中是否出现某数,并在搜索时进行回溯,其中需要注意的是如何判断当前的最小格是隶属于哪个小的3*3的九宫格的,我们通过尝试和思考发现对于用0~8表示行列的九宫格,我们用x表示行,用y表示列,那么我们vk[x/3*3+y/3][i]表示这个3*3小的九宫格是否出现了数字i,最后输出九宫格即可
代码如下:
#include<bits/stdc++.h> using namespace std; int mp[10][10],vx[10][10],vy[10][10],vc[10][10]; void dfs(int x,int y) { if(x==9) { for(int i=0; i<9; i++) { for(int j=0; j<9; j++) { cout<<mp[i][j]<<" "; } cout<<endl; } return ; } if(y==9) { dfs(x+1,0); return ; } if(mp[x][y]) dfs(x,y+1); else for(int i=1; i<=9; i++) { if(!vx[x][i] && !vy[y][i] && !vc[x/3*3+y/3][i]) { mp[x][y] =i; vx[x][i] =1; vy[y][i] =1; vc[x/3*3+y/3][i] =1; dfs(x,y+1); mp[x][y]=0; vx[x][i] =0; vy[y][i] =0; vc[x/3*3+y/3][i] =0; } } } int main() { for(int i=0; i<9; i++) { for(int j=0; j<9; j++){ cin>>mp[i][j]; vx[i][mp[i][j]]=1; vy[j][mp[i][j]]=1; vc[i/3*3+j/3][mp[i][j]]=1; } } dfs(0,0); return 0; }
接下来我们做P1074靶向数独的时候就有了一定的基础了,该题只是在数独上做了一些延伸,即需要每一步记录分数,大体基本不变,只是添加一个分数的参数的话,并在搜索完成后比较最大值,注意如果没有结果,就直接输出-1,那我们不妨将ans一开始定义为-1,这样如果没有答案的话是无法进行最后一步的比较的,就直接输出-1,接下来我们需要打一个表(也可以不打表,但需要一种类似处理所在3*3九宫格位置的方法,留给读者思考),记录不同位置对应靶的分数,这样处理后提交发现T了几个点,我们就需要优化如何优化,似乎无法进行最优化和可行性剪枝。我们思考一下,是否现实中我们在做数独题的时候,我们总是先将数字最多的一个部分先填满,以便后续的推理,这里的优化思想就来源于这种思想,我们需要一个记录每一行元素个数的数组,它同时也要记忆当前的真实行数,并最后从大到小排序,我们从元素最多的一行开始搜索,这样就能完美解决这一问题了。
代码如下:
#include<iostream> #include<cstdio> #include<algorithm> using namespace std; int mp[10][10],vc[10][10],vr[10][10],vk[10][10],ans=-1; int biao[10][10]={ {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,0}, }; struct node{ int cnt,v; friend bool operator <(const node& a,const node& b) { return a.cnt>b.cnt; } }s[10]; void dfs(int x,int y,int sum){ int temp = s[x].v; if(x==9) { ans = max(ans,sum); return ; } if(y==9){ dfs(x+1,0,sum); return ; } if(mp[temp][y]) dfs(x,y+1,sum+biao[temp][y]*mp[temp][y]); else for(int i=1; i<=9; i++) { if(!vc[temp][i]&&!vr[y][i]&&!vk[temp/3*3+y/3][i]) { vc[temp][i]=1; vr[y][i]=1; vk[temp/3*3+y/3][i]=1; mp[temp][y]=i; dfs(x,y+1,sum+biao[temp][y]*i); vc[temp][i]=0; vr[y][i]=0; vk[temp/3*3+y/3][i]=0; mp[temp][y]=0; } } } int main() { for(int i=0; i<9; i++) { s[i].v=i; for(int j=0; j<9; j++) { cin>>mp[i][j]; vc[i][mp[i][j]]=1; vr[j][mp[i][j]]=1; vk[i/3*3+j/3][mp[i][j]]=1; if(mp[i][j]) s[i].cnt++; } } sort(s,s+9); dfs(0,0,0); cout<<ans; return 0; }