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

来源:互联网 发布:数据分析师主要做什么 编辑:程序博客网 时间:2024/05/18 02:38

上次我们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;}


0 0
原创粉丝点击