惯例的搜寻是很容易想到的,不再详述。

如果你浏览过 Matrix67 的博客中八皇后问题对于 位运算的优化,此题也有相似的优化伎俩,而且此题比原题简略得多。

先放代码,上面是剖析。

/*#include <iostream>#include <cmath>#include <cstdio>#include <algorithm>#include <cstring>#include <functional>*/#include "lab.h"//预编译头typedef long long ll;#define    _fora(i,a,n)    for(ll i=(a);i<=(n);i++)#define    _forz(i,a,n)    for(ll i=(a);i>=(n);i--)#define    _forb(i,a)        for(ll i=(a);i>0;i-=i&(-i))using namespace std;int n,k;int nn[10];int sum(int n) {    int rst = 0;    _forb(i,n)        rst++;    return rst;}int dfs(int tn,int prv,int a) {    int rst = 0;    int ans = (~prv) & nn[tn];    if(tn+a < n)        rst += dfs(tn+1,prv,a);    if(a == 1) {        rst += sum(ans);        return rst;    }    _forb(i,ans) {        rst += dfs(tn+1,prv|(i&(-i)),a-1);    }    return rst;}int main() {    while(scanf("%d %d", &n,&k) != EOF) {        if(n+k<0)            break;        char ch[10][10];        nn[n] = (1<<n)-1;        _fora(ia,0,n-1) {            scanf("%s",ch[ia]);            nn[ia] = 0;            _fora(ib,0,n-1) {                nn[ia] = nn[ia] << 1;                if(ch[ia][ib] == '#')                    nn[ia] += 1;            }        }        printf("%d\n", dfs(0,0,k));    }    return 0;}

题解 2020-09-24

请先浏览 Matrix67 的博客,我不感觉我能讲的比他好。

如不理解运算 x&(-x),请查阅 lowbit 或者树状数组相干信息。

咱们来看怎么把同样的思维套进此题里。因为 n 最大只有 8,int 塞下一整行入不敷出。

main 里先读入,按位初始化到 int nn[10]。如果第t行是 ..#.,那么 nn[t] = 0b0010。

要害在搜寻 dfs(tn,prv,a)。其中 tn 为到了第几行,a 为还剩多少棋子,prv 是已搁置的信息,返回值是答案。

int dfs(int tn,int prv,int a);

那么 prv 取反即是以后行不抵触信息,nn[tn] 是以后行棋盘信息,相与失去 ans,即为以后行可搁置信息。

int ans = (~prv) & nn[tn];

如果 tn+a < n,能够思考这一行不放。

if(tn+a < n)    rst += dfs(tn+1,prv,a);

如果 a = 1,阐明棋子曾经全副搁置,计算 ans 中 1 的个数并返回。

if(a == 1) {    rst += sum(ans);    return rst;}

外围局部,ans 蕴含了整行的可搁置信息,能够通过 lowbit 取出低位地位。

所以应用宏 _forb 一直循环 i ,则 lowbit(i) 是每个可搁置地位,用或运算把此地位退出已搁置信息,递归进入下一行。

_forb(i,ans) {    rst += dfs(tn+1,prv|(i&(-i)),a-1);}

以上。