题目连接
题目大意
- 一个9*9的数独,带权值,求填写数独的基础上,总权值最高;
- 要求1:权值是各个格子的值*分数的和;
- 各个格子的分数分布,类似一个标靶,所以叫靶形数独;
题目分析
- 基础的数独问题加上优化;
- 优化的思想也不难理解:不要盲目地按照行列填写,找点方法!
解题思路
- 每次都从全图中找“当前选择最少的点”,然后再尝试填数;
- 本题的搜索参数,其实没有太大的用处,所以随便写了个剩余格子,作为dfs()的参数
- 最卡时间的应该是每次的全图查找,注意注意注意注意!
上代码
//luogu1074:靶形数独
//解题思路:
//还是深搜,但是用了个剪枝的思维
//每次去下一个点前,找出全图“能选最少数”的点,搜它。(剪掉很多)
//思路和手动填数独一样,先找最容易填的!
// (这样将“多搜索次数的点”尽可能往后推,让树干的枝尽可能少)
#include
using namespace std;
int a[20][20];
int h[20][20],l[20][20],g[20][20];
int fh[20],fl[20],n=81,ans=-1;
int f[20][20]={
{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}};
int fg(int x,int y) { return (x-1)/3*3+(y-1)/3+1; }//求宫
void inp()//输入与预处理
{
memset(h,0,sizeof(h));
memset(l,0,sizeof(l));
memset(g,0,sizeof(g));
for(int i=1;i<=9;i++) fh[i]=9,fl[i]=9;//每行每列都可以填9个数字
int x;
for(int i=1;i<=9;i++)
{
for(int j=1;j<=9;j++)
{
scanf("%d",&x);
if(x>0)
{
h[i][x]=1;l[j][x]=1;g[fg(i,j)][x]=1;
fh[i]--; fl[j]--;
n--;
}
a[i][j]=x;
}
}
}
struct nod{int x,y;};
nod pd()//返回当前选择最少的格子
{
int sx=10,sy=10;
int x,y;
for(int i=1;i<=9;i++)
{
if(fh[i]>0&&fh[i]0||l[y][i]>0||g[fg(x,y)][i]>0) continue;
a[x][y]=i;
h[x][i]=1; l[y][i]=1; g[fg(x,y)][i]=1;
fh[x]--; fl[y]--;
dfs(t-1);
a[x][y]=0;
h[x][i]=0; l[y][i]=0; g[fg(x,y)][i]=0;
fh[x]++; fl[y]++;
}
}
int main()
{
inp();
nod s=pd();//查找当前选择最少的格子;
int x=s.x,y=s.y;
for(int i=1;i<=9;i++)//先封路,再搜
{
if(h[x][i]==0&&l[y][i]==0&&g[fg(x,y)][i]==0)
{
a[x][y]=i; h[x][i]=1; l[y][i]=1; g[fg(x,y)][i]=1;
fh[x]--; fl[y]--;
dfs(n-1);
a[x][y]=0; h[x][i]=0; l[y][i]=0; g[fg(x,y)][i]=0;
fh[x]++; fl[y]++;
}
}
printf("%d",ans);
return 0;
}