luogu1074:靶形数度:数迷问题+填数顺序优化

题目连接

  • 该题是luogu试炼场的2-9:T4

题目大意

  1. 一个9*9的数独,带权值,求填写数独的基础上,总权值最高;
  2. 要求1:权值是各个格子的值*分数的和;
  3. 各个格子的分数分布,类似一个标靶,所以叫靶形数独;

题目分析

  • 基础的数独问题加上优化;
  • 优化的思想也不难理解:不要盲目地按照行列填写,找点方法!

解题思路

  1. 每次都从全图中找“当前选择最少的点”,然后再尝试填数;
  2. 本题的搜索参数,其实没有太大的用处,所以随便写了个剩余格子,作为dfs()的参数
  3. 最卡时间的应该是每次的全图查找,注意注意注意注意!

上代码

//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;
}


你可能感兴趣的:(题解,深搜,题表,luogu,大礼包,luogu1074,靶形数独,数迷问题)