noip2009靶形数独(优化搜索顺序+位运算(只是常数优化,快一点))

搜索,如果先从密集的地方开始搜索,会好一点,显然是这样,这道题就利用了这一点,找较密集的行先搜索


位运算,用一个数字来代表这一行放了哪些

下面两种思路都过了,第一种稍微快一点,但不如第二种直观,实际上两种就差几十ms而以

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int sc[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};
const int pos[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};   
struct aa
{
	int x,y;
	bool operator <(const aa &b)const
	{
		return y>b.y;
	}
}a[82],k[11];
					  
int qx[10],qy[10],qk[10],r=0;
int map[10][10],tot,ans=-1;
int lowbit(int x)
{
	return x&(-x);
}
void dfs(int i,int z)
{
	if (i>tot) 
	{
		if (z+r>ans)ans=z+r;
		return ;
	}
	int x=a[i].x,y=a[i].y;
	int k=qx[x]&qy[y]&qk[pos[x][y]];//用一个数字代表在行列宫里面是否可放,充分利用了&的特性,注意这里k&1表示可放

	int h,cou;
	while (k)
	{
		h=lowbit(k);
		qx[x]^=h;
		qy[y]^=h;
		qk[pos[x][y]]^=h;
		cou=1;
		while ((h>>cou)>0)cou++;
		dfs(i+1,z+(cou-1)*sc[x][y]);
		qk[pos[x][y]]^=h;
		qy[y]^=h;
		qx[x]^=h;
		k^=h;
	}
}
int main()
{
	for (int i=1;i<=9;i++) qx[i]=qy[i]=qk[i]=(1<<10)-2;//初始化

	for (int i=1;i<=9;i++)
	{
		k[i].x=i;
		for (int j=1;j<=9;j++) 
		{
			scanf("%d",&map[i][j]);
			if (map[i][j])
			{
				r+=sc[i][j]*map[i][j];
				k[i].y++;
				qk[pos[i][j]]^=1<<map[i][j];
				qy[j]^=1<<map[i][j];
				qx[i]^=1<<map[i][j];
			}
		}
	}
	sort(k+1,k+10);
	for (int i=1;i<=9;i++)
	{
		int h=k[i].x;
		for (int j=1;j<=9;j++)
		if (map[h][j]==0)
		{
			a[++tot].x=h;
			a[tot].y=j;
		}
	}//优化搜索顺序
	int l=1;
	dfs(1,0);
    printf("%d",ans);
	return 0;	
  }  

第二种

#include<cstdio>
#include<algorithm>
#include<cstring>

using namespace std;

const int sc[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};
const int pos[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};   
struct aa
{
	int x,y;
	bool operator <(const aa &b)const
	{
		return y>b.y;
	}
}a[82],k[11];
					  
int qx[10],qy[10],qk[10],r=0;
int map[10][10],tot,ans=-1;
int lowbit(int x)
{
	return x&(-x);
}
void dfs(int i,int z)
{
	if (i>tot) 
	{
		if (z+r>ans)ans=z+r;
		return ;
	}
	int x=a[i].x,y=a[i].y;
	int k=qx[x]&qy[y]&qk[pos[x][y]];
	for (int j=1;j<=9;j++) if (k&(1<<j))
	{
		k^=(1<<j);
		qx[x]^=1<<j;
		qy[y]^=1<<j;
		qk[pos[x][y]]^=1<<j;
		dfs(i+1,z+j*sc[x][y]);
		qk[pos[x][y]]^=1<<j;
		qy[y]^=1<<j;
		qx[x]^=1<<j;
		k^=(1<<j);
	}
}
int main()
{
	for (int i=1;i<=9;i++) qx[i]=qy[i]=qk[i]=(1<<10)-2;
	for (int i=1;i<=9;i++)
	{
		k[i].x=i;
		for (int j=1;j<=9;j++) 
		{
			scanf("%d",&map[i][j]);
			if (map[i][j])
			{
				r+=sc[i][j]*map[i][j];
				k[i].y++;
				qk[pos[i][j]]^=1<<map[i][j];
				qy[j]^=1<<map[i][j];
				qx[i]^=1<<map[i][j];
			}
		}
	}
	sort(k+1,k+10);
	for (int i=1;i<=9;i++)
	{
		int h=k[i].x;
		for (int j=1;j<=9;j++)
		if (map[h][j]==0)
		{
			a[++tot].x=h;
			a[tot].y=j;
		}
	}
	int l=1;
	dfs(1,0);
    printf("%d",ans);
	return 0;	
  }  




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值