靶型数独 洛谷P1074

题目描述

小城和小华都是热爱数学的好学生,最近,他们不约而同地迷上了数独游戏,好胜的他们想用数独来一比高低。但普通的数独对他们来说都过于简单了,于是他们向 Z 博士请教,Z 博士拿出了他最近发明的“靶形数独”,作为这两个孩子比试的题目。

靶形数独的方格同普通数独一样,在 99 格宽×99 格高的大九宫格中有9 9 个 33 格宽×33 格高的小九宫格(用粗黑色线隔开的)。在这个大九宫格中,有一些数字是已知的,根据这些数字,利用逻辑推理,在其他的空格上填入 11 到 9 9的数字。每个数字在每个小九宫格内不能重复出现,每个数字在每行、每列也不能重复出现。但靶形数独有一点和普通数独不同,即每一个方格都有一个分值,而且如同一个靶子一样,离中心越近则分值越高。(如图)

在这里插入图片描述

上图具体的分值分布是:最里面一格(黄色区域)为 1010 分,黄色区域外面的一圈(红色区域)每个格子为 9 9分,再外面一圈(蓝色区域)每个格子为 88 分,蓝色区域外面一圈(棕色区域)每个格子为 7 7分,最外面一圈(白色区域)每个格子为 6 6分,如上图所示。比赛的要求是:每个人必须完成一个给定的数独(每个给定数独可能有不同的填法),而且要争取更高的总分数。而这个总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和

总分数即每个方格上的分值和完成这个数独时填在相应格上的数字的乘积的总和。如图,在以下的这个已经填完数字的靶形数独游戏中,总分数为 2829。游戏规定,将以总分数的高低决出胜负。

由于求胜心切,小城找到了善于编程的你,让你帮他求出,对于给定的靶形数独,能够得到的最高分数。

输入输出格式

输入格式:
一共 99 行。每行 9 9个整数(每个数都在 0-90−9 的范围内),表示一个尚未填满的数独方格,未填的空格用“00”表示。每两个数字之间用一个空格隔开。

输出格式:
输出共 11 行。输出可以得到的靶形数独的最高分数。如果这个数独无解,则输出整数-1−1。

输入输出样例

输入样例#1: 复制
7 0 0 9 0 0 0 0 1
1 0 0 0 0 5 9 0 0
0 0 0 2 0 0 0 8 0
0 0 5 0 2 0 0 0 3
0 0 0 0 0 0 6 4 8
4 1 3 0 0 0 0 0 0
0 0 7 0 0 2 0 9 0
2 0 1 0 6 0 8 0 4
0 8 0 5 0 4 0 1 2
输出样例#1: 复制
2829
输入样例#2: 复制
0 0 0 7 0 2 4 5 3
9 0 0 0 0 8 0 0 0
7 4 0 0 0 5 0 1 0
1 9 5 0 8 0 0 0 0
0 7 0 0 0 0 0 2 5
0 3 0 5 7 9 1 0 8
0 0 0 6 0 1 0 0 0
0 6 0 9 0 0 0 0 1
0 0 0 0 0 0 0 0 6
输出样例#2: 复制
2852
说明

【数据范围】

40%的数据,数独中非 00 数的个数不少于 3030。

80%的数据,数独中非 00 数的个数不少于2626。

100%的数据,数独中非0 0数的个数不少于 2424。

NOIP 2009 提高组 第四题

分析

dfs(不打表),用一个序列s[ ]保存要填的点,dfs携带的参数就是要填写的点的坐标:
s[ i ][0]与s[ i ][1]存点的坐标,s[ i ][2]存点的分值,s[ i ][3]存点的所在宫(我用函数现生成,避免了打表)。
需要注意的有如下几点:
一、dfs过程中就判断数能不能放,别放到最后判断(这一条可能是废话)实现方法用三个数组分别存各行、列、宫每个数字的状态(0表示没填过,1表示填过)
(重要)二、dfs层数与0的个数有关,层数太多就TLE了,我们知道,一行中填过的数字越多,需要填的数越少,就意味着dfs层数越少!所以,我们先填0的数量少的行。(详细实现见代码)
不懂的看这:)
0 0 0 0 0 0 0 0 0 //这一行有9个0
1 0 0 0 0 5 9 0 0 //这一行有6个0
0 0 0 2 0 0 0 8 0 //这一行有7个0
0 0 5 0 2 0 0 0 3 //这一行有6个0
0 0 0 0 0 0 6 4 8 //这一行有6个0
4 1 3 0 0 0 0 0 0 //这一行有6个0
0 0 7 0 0 2 0 9 0 //这一行有6个0
2 0 1 0 6 0 8 0 4 //这一行有4个0
0 8 0 5 0 4 0 1 2//这一行有4个0
在这个例子中,从第一行到第九行dfs的话,那么dfs第一层就有9种情况!!!根据dfs的原理,从第一层9种情况开始拓展,那么时间就要花很多。而若从第8层开始只有4种情况,搜索需要的时间就大大减少。TLE再见!!

代码

#include<bits/stdc++.h>
using namespace std;
const int M=102,N=12;
bool h[N][N],l[N][N],p[N][N];//行,列,宫有没有填过相同的数字 
int m[M][4],a[M][M],wz,ans=-1,fs,wzz;
struct A
{
	int fh,z;
}k[N];
int which(int x,int y)//哪一个宫 
{
	if(x<=3)
	{
		if(y<=3) return 1;
		if(y<=6) return 2;
		return 3;
	}
	if(x<=6)
	{
		if(y<=3) return 4;
		if(y<=6) return 5;
		return 6;
	}
	if(x<=9)
	{
		if(y<=3) return 7;
		if(y<=6) return 8;
		return 9;
	}
}
int point(int x,int y)//这个点有几分 
{
	if(x==1||y==1||x==9||y==9) return 6;
	if(x==2||y==2||x==8||y==8) return 7;
	if(x==3||y==3||x==7||y==7) return 8;
	if(x==4||y==4||x==6||y==6) return 9;
	return 10;
}
bool cmp(A x,A y)
{
	return x.z<y.z;
}
void dfs(int u,int afs)
{
	if(u==wzz)
	{
		ans=max(ans,afs);
		return;
	}
	for(int i=1;i<=9;i++)//1~9填入 
	 if(!h[m[u][0]][i]&&!l[m[u][1]][i]&&!p[m[u][3]][i])//可以填 
	 {
	 	h[m[u][0]][i]=l[m[u][1]][i]=p[m[u][3]][i]=1;
	 	dfs(u+1,afs+(m[u][2]*i));
	 	h[m[u][0]][i]=l[m[u][1]][i]=p[m[u][3]][i]=0;
	 }
}
int main()
{
	for(int i=1;i<=9;i++)
	 k[i].fh=i;
	for(int i=1;i<=9;i++)
	 for(int j=1;j<=9;j++)
	 {
	 	scanf("%d",&a[i][j]);
	 	if(a[i][j]>0)
	 	 h[i][a[i][j]]=l[j][a[i][j]]=p[which(i,j)][a[i][j]]=1,fs+=a[i][j]*point(i,j);
	 	else
	 	 k[i].z++;
	 }
	 sort(k+1,k+10,cmp);//先填0少的
	 for(int i=1;i<=9;i++)
	  for(int j=1;j<=9;j++)
	   if(a[k[i].fh][j]==0)//要填数字
	    m[wzz][0]=k[i].fh,m[wzz][1]=j,m[wzz][2]=point(k[i].fh,j),m[wzz++][3]=which(k[i].fh,j);
	dfs(0,fs);
	printf("%d",ans); 
}

猜你喜欢

转载自blog.csdn.net/qq_43034907/article/details/82901460
今日推荐