n皇后问题
递归算法
bool valid(vector<int> &res, int r) { int nCol = res.size(); for(int i=0;i<nCol;i++){ if(res[i]==r || abs(res[i]-r)==nCol-i){ return false; } } return true; } void queen(int n, int l, vector<int> res, int &nCount) { if (l == n) { nCount++; return; } for (int i=0; i<n; i++) { if (!valid(res, i)) continue; res.push_back(i); queen(n, l+1, res, nCount); res.pop_back(); } } int totalNQueens(int n) { vector<int> vec; int nCount = 0; queen(n, 0, vec, nCount); return nCount; }
非递归算法:
int place(vector<int> &x, int k) { int j; for (j = 0; j < k; j++) { if ((abs(k - j) == abs(x[j] - x[k])) || (x[j] == x[k])) return 0; } return 1; } int totalNQueens1(int n) { vector<int> x(n); int nCount = 0; for (int i = 0; i < n; i ++) { x[i] = 0; } x[0] = -1; int k = 0; while (k >= 0) { x[k] += 1; while ((x[k] < n) && !(place(x, k))) x[k] += 1; if (x[k] < n) { if (k == n - 1) nCount++; else { k++; x[k] = -1; } } else k--; } return nCount; }
最高效的算法
#include <stdio.h> #include <stdlib.h> #include <time.h> long sum = 0, upperlim = 1; void test(long row, long ld, long rd) \\row表示已经有皇后的行,ld、rd分别表示已经有皇后的斜列,每一位表示该列中可以摆放皇后的位置,1表示可以摆放,0表示不可以摆放。row在每查找下一列时不用改动,ld、rd需要分别左移和右移一位。 { if (row != upperlim) \\当所有行都有皇后时说明摆放完毕 { long pos = upperlim & ~(row | ld | rd); \\pos的每一位表示该列中可以摆放皇后的位置,1表示可以摆放,0表示不可以摆放 while (pos) \\如果pos中还有可以摆放的位置 { long p = pos & -pos; \\p为pos中最末一个可以摆放的位置 pos -= p; \\将p从可摆放位置去掉 test(row + p, (ld + p) << 1, (rd + p) >> 1); \\对下一列进行判断 } } else sum++; } int main(int argc, char *argv[]) { time_t tm; int n = 16; if (argc != 1) n = atoi(argv[1]); tm = time(0); if ((n < 1) || (n > 32)) { printf(" 只能计算1-32之间\n"); exit(-1); } printf("%d 皇后\n", n); upperlim = (upperlim << n) - 1; test(0, 0, 0); printf("共有%ld种排列, 计算时间%d秒 \n", sum, (int) (time(0) - tm)); }