USACO 1.4 Checker Challenge 位运算

Test 1: TEST OK [0.003 secs, 3372 KB] Test 2: TEST OK [0.003 secs, 3372 KB] Test 3: TEST OK [0.003 secs, 3372 KB] Test 4: TEST OK [0.003 secs, 3372 KB] Test 5: TEST OK [0.003 secs, 3372 KB
摘要由CSDN通过智能技术生成

   Test 1: TEST OK [0.003 secs, 3372 KB]
   Test 2: TEST OK [0.003 secs, 3372 KB]
   Test 3: TEST OK [0.003 secs, 3372 KB]
   Test 4: TEST OK [0.003 secs, 3372 KB]
   Test 5: TEST OK [0.003 secs, 3372 KB]
   Test 6: TEST OK [0.008 secs, 3372 KB]
   Test 7: TEST OK [0.011 secs, 3372 KB]
   Test 8: TEST OK [0.078 secs, 3372 KB]



简]单介绍一下思想。

用位运算的方法来求的数量,DFS暴力搜索,搜出前3个答案。

还有一个就是棋盘是左右对称的,8*8的棋盘,第一个旗子放在第一排的前四个,和后四个结果应该完全一样。

对于棋盘n的奇偶分情况考虑一下就行了。 对半剪枝,实际上已经可以通过了。

对于非位运算的搜索还有一个优化,就是对于列是否被占用的判断,可以直接用链表,利用dancing link的思想,在穷举到最后的矩阵是很稀疏的,节约了穷举的时间。其实只加这一个优化不对半剪枝也是可以通过的~


当然最强的还是位运算,应为他对于穷举可以占用的格子的效率是最高的。

用3个数字分别表示,第deep行,每个格子的列,左斜排,右斜排是否被占用。

因为  对于deep行,他的左斜排被占用的是第一个,第二个格子。 那么deep+1行的时候,就是第0个,第一个格子。 说白了,就是这些会占用斜排的情况,在deep+1的时候,是会位移的。


位移?当然就是位运算的shl  shr了~ 到这里基本方法就出来了。  听说这是穷举N皇后最快的方法。不知道用bitset的STL的话效率怎么样。


	ultimate = (1 << n) - 1;

ultimate是用来表示一个n位的二进制全是1的数字。 这个应该不复杂。


/*
TASK:checker
LANG:C++
*/
#include <cstdio>

int ultimate, n, ans(0);
int tmp,outputbuff[13],ifstop=0;;
bool a[3][35] = {0};

void dfs(int row, int ld, int rd)
{
	if (row == ultimate)
	{
		++ ans;
		return;	
	}
	rd >>= 1, ld <<= 1;
	int tmp = row | ld | rd, p, ok = (~(row | ld | rd)) & ultimate;
	while (ok)
	{
		p = ok & -ok;
		dfs(row | p, ld | p, rd | p);
		ok ^= p;
	}
}

void get_ans(int deep)
{
	if (ifstop == 3)	return;
	if (deep == n)
	{
		++ifstop;
		for (int i = 0; i != n - 1; ++ i)	printf("%d ",outputbuff[i] + 1);
		printf("%d\n", outputbuff[n - 1] + 1);
		return;	
	}
	for (int i = 0; i != n; ++ i)
		if (!a[0][i] && !a[1][deep - i + n + 1] && !a[2][i + deep])
		{
			a[0][i] = a[1][deep - i + n + 1] = a[2][i + deep] = 1;
			outputbuff[deep] = i;
			get_ans(deep + 1);
			a[0][i] = a[1][deep - i + n + 1] = a[2][i + deep] = 0;
		}
}

int main()
{
	freopen("checker.in", "r", stdin);
	freopen("checker.out", "w", stdout);
	scanf("%d",&n);	
	get_ans(0);
	ultimate = (1 << n) - 1;
#define p (1<<(i-1))
	for (int i = 1; i <= (tmp = n >> 1); ++ i)	dfs(p, p, p);
	ans <<= 1;
	if (n&1)	dfs(1 << tmp, 1 << tmp, 1 << tmp);
	printf("%d\n", ans);
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值