其实这个问题老早之前我就做过了,但之前一直没发。
首先很容易想到使用枚举的方法
使用一个树结构来枚举
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
| void f(int layer,int* prev_queen){ int available[n]; for(int i=0;i<n;i++){ available[i]=1; } for(int i=0;i<layer;i++){ int position=prev_queen[i]; available[position]=0; int offset=layer-i; int left=position-offset; int right=position+offset; if(left>=0){ available[left]=0; } if(right<n){ available[right]=0; } } for(int i=0;i<n;i++){ if(available[i]){ if(layer==n-1){ count++; return; } auto prev_queen_this=copy(prev_queen); prev_queen_this[layer]=i; f(layer+1,prev_queen_this); } } }
|
思考
不难发现,其实这个树的遍历用的是深度优先,我们根本没有必要复制一次这个prev_queen
。
因为每次到达叶子节点的时候都能保证prev_queen
中的值是正确的。
优化后完整代码如下
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| #include "iostream" using namespace std;
int count=0; const int n=8; int prev_queen[n]; void f(int layer){ int available[n]; for(int i=0;i<n;i++){ available[i]=1; } for(int i=0;i<layer;i++){ int position=prev_queen[i]; available[position]=0; int offset=layer-i; int left=position-offset; int right=position+offset; if(left>=0){ available[left]=0; } if(right<n){ available[right]=0; } } for(int i=0;i<n;i++){ if(available[i]){ if(layer==n-1){ count++; return; } prev_queen[layer]=i; f(layer+1); } } }
int main(){ f(0); cout<<count<<endl; return 114514; }
|