AOJ-AHU-OJ-453 棋盘问题(位压缩)

37 篇文章 0 订阅
14 篇文章 0 订阅

上次我们DFS解决了棋盘问题。但是一跑……140+ms QAQ 看到别人20+ms AC了,深感愧疚。

这次我们对棋盘问题的解决方式做空间和时间上的优化。让它优美地AC

1.考虑空间问题。我们把棋盘作为地图保存了下来。有的地方是0可以放置棋子,有的地方是-1不能放置棋子。而且还做了每列的标记,放了棋子则该标记为1。我们发现,0/1 这个计算机唯一认识的两个符号是解决该问题的关键。“位运算”。——在二进制下,一个数字只能表示为10010010或01101101这样的形式。反过来想一下,这样的形式不只可以表示其他进制的数字,还可以表示地图!

这就牵扯到位压缩的问题。棋盘上每一行的状况(反正是最大8×8棋盘),我们用一个int数表示。比如00000010(B)表示倒数第2列有一个棋子,枚举的时候,& 一下,就可以判断该列能不能放。

2.考虑时间问题。想一想,假如我已经放置了一些棋子,手里还剩下5个棋子需要放置,棋盘下面只剩下4行没有枚举。我还继续枚举一遍?浪费时间!

代码如下:

#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int ans;
int n, k;
char str[10][10];
int  line;
void dfs(int cur, int r){
	if(k - cur > n - r) return;//一旦剩下的棋子大于剩下的行,回城
	if(cur == k){
		ans++;
		return;
	}
	for(int i = 0; i < n; i++){
                //↓此处是‘#’可以放置      //↓该列没有放置棋子
		if(str[r][i] == '#' && !(line & (1<<i))){
			line |= 1 << i;//在本层递归中,第 r 行 i 列被置为1,放置该棋子
			dfs(cur+1, r+1);//递归下一个棋子,访问下一行
			//完成本层递归,在此之前,进入下面的dfs,即假设没有放下棋子
			line ^= 1 << i;//清除此处已经放置棋子的标记
		}
	}
	dfs(cur, r+1);//递归没有放置该棋子的情况
}
int main(){
	//freopen("input.txt","r",stdin);
	while(scanf("%d%d", &n, &k) != EOF && (n != -1||k != -1)){
		ans = line = 0;
		for(int i = 0; i < n; i++)
			scanf("%s", str[i]);
		dfs(0, 0);
		printf("%d\n", ans);
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值