编程题目《NOIP2009_T4_靶形数独》总结(不可思议的一道题)


编程题目《NOIP2009_T4_靶形数独》总结(不可思议的一道题) - 哭,等谁回眸 - 哭,等谁回眸
编程题目《NOIP2009_T4_靶形数独》总结(不可思议的一道题) - 哭,等谁回眸 - 哭,等谁回眸
编程题目《NOIP2009_T4_靶形数独》总结(不可思议的一道题) - 哭,等谁回眸 - 哭,等谁回眸
编程题目《NOIP2009_T4_靶形数独》总结(不可思议的一道题) - 哭,等谁回眸 - 哭,等谁回眸
 
爆搜加优化!
代码如下:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstdlib>
using namespace std;
const int s[10][10]={0,0,0,0,0,0,0,0,0,0,
		     0,1,1,1,2,2,2,3,3,3,
		     0,1,1,1,2,2,2,3,3,3,
		     0,1,1,1,2,2,2,3,3,3,
	             0,4,4,4,5,5,5,6,6,6,
		     0,4,4,4,5,5,5,6,6,6,
		     0,4,4,4,5,5,5,6,6,6,
		     0,7,7,7,8,8,8,9,9,9,
		     0,7,7,7,8,8,8,9,9,9,
		     0,7,7,7,8,8,8,9,9,9};//每个九宫格的预处理。
const int p[10][10]={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};//分值。
bool line[10][10],row[10][10],ss[10][10],c[10][10];
int xx,yy,n,num,i,j,ans,k,m,now,last,cnt,a[10][10],f[10][10];//f是限制数组。
struct dong
{
	int x,y;
}d[100];//d为枚举顺序。
inline void zbj(int i,int j)//找到i,j九宫格的左上角。笨方法!!
{
	if(i<=3) xx=1;
	else 
	{
		if(i<=6) xx=4;
		else xx=7;
	}
	if(j<=3) yy=1;
	else 
	{
		if(j<=6) yy=4;
		else yy=7;
	}
} 
inline void nyh(int k)//寻找第k多0的位置。
{
	int max=0,x,y,i,j;
	for(i=1;i<=9;i++)
		for(j=1;j<=9;j++)
			if(c[i][j]&&f[i][j]>max) 
			{
				max=f[i][j];
				x=i;
				y=j;
			}
	d[k].x=x;
	d[k].y=y;
	for(i=1;i<=9;i++)
	{
		f[i][y]++;
		f[x][i]++;
	}
	zbj(x,y);
	for(i=xx;i<=xx+2;i++)//同main中的预处理。
		for(j=yy;j<=yy+2;j++)
			f[i][j]++;
	c[x][y]=false;
}  
void lyd(int k)//dfs
{
	if(k==num+1)//边界。
	{
		if(now>ans) ans=now;
		return;
	}  
	int x=d[k].x;int y=d[k].y;
	for(int i=1;i<=9;i++)
		if(line[x][i]&&row[y][i]&&ss[s[x][y]][i])                        
		{
			now+=i*p[x][y];
			line[x][i]=false;
			row[y][i]=false;
			ss[s[x][y]][i]=false;
			lyd(k+1);//递归!
			now-=i*p[x][y];//以下为回溯。
			line[x][i]=true;
			row[y][i]=true;
			ss[s[x][y]][i]=true;
		}
}
int main()
{
	memset(line,1,sizeof(line));//line标记列。
	memset(row,1,sizeof(row));//row标记行
	memset(ss,1,sizeof(ss));//ss预处理该九宫格。
	for(i=1;i<=9;i++)
		for(j=1;j<=9;j++)
		{
			scanf("%ld",&a[i][j]);
			if(a[i][j]>0) 
			{
				line[i][a[i][j]]=false;
				row[j][a[i][j]]=false;
				ss[s[i][j]][a[i][j]]=false;
				last+=a[i][j]*p[i][j];//以上是对已有的分值进行预处理。
				for(k=1;k<=9;k++)
				{
					f[i][k]++;
					f[k][j]++;
				}
				zbj(i,j);
				for(k=xx;k<=xx+2;k++)
					for(m=yy;m<=yy+2;m++)
						f[k][m]++;                                   
			}
			else 
			{
				num++;
				c[i][j]=true;
			}
		}
	for(i=1;i<=num;i++) nyh(i);//对于没有处理的数,从简单的(多0的)先来填补,附加上数独的规则即可。
	ans=-1;
	lyd(1);
	if(ans==-1) last=0;
	printf("%ld\n",ans+last);
	return 0;
}


先说题,裸搜谁都会,但是至于优化,其实我也说不出来,我的不同在于使用了一个f数组来限制我的dfs,从而使时间缩短,不过具体这个f我也用的迷迷糊糊的,只能说是运气好,蒙对了,其他的就没什么可说的了,比赛时我自诩也打不出这样的代码,还是裸搜的性价比更高一些,也能拿到比较实惠的分数。
这道题同学都说很难,但我不觉的,可能是因为运气吧,但是我觉得有以下几点:①dfs我已经有一段时间没有再练过了,再看到一个dfs的题,之前在脑海里关于dfs的沉淀与大脑有了不错的磨合,所以做起来比较顺畅②我之前看过这道题,不过没有去写,只是偶尔的想想,比起那些非要在一天什么都不干也要A掉这道题的同学强,或许是当局者迷吧,再一看到这道题,以前的思路就源源不断的涌现出来了,所以,我认识到,平时的思考是非常重要的,它会在意想不到的地方带来意想不到的惊喜!
好了,这道题就到这里吧!
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值