您的位置:首页 > 其它

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

2014-03-11 20:41 225 查看
上次我们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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: