Follow up for N-Queens problem.
Now, instead outputting board configurations, return the total number of distinct solutions.
思路1:打表
public class Solution { public int totalNQueens(int n) { int[] result = new int[] { 0, 1, 0, 0, 2, 10, 4, 40, 92, 352, 724, 2680, 14200, 73712, 365596, 2279184, 14772512, 95815104, 666090624 }; return result[n]; } }
思路2:使用回溯法,参照http://blog.csdn.net/mlweixiao/article/details/40984541
public class Solution { public static int num=0; private boolean isValid(List<Integer> al) { int column = al.get(al.size() - 1); for (int i = 0; i < al.size() - 1; i++) { if (column == al.get(i) || Math.abs(column - al.get(i)) == Math.abs(al.size()-1 - i)) { return false; } } return true; } private void search(int n, List<Integer> al, int col) { if (col > n){ num++; }else { for (int j = 0; j < n; j++) { al.add(j); if (isValid(al)) { search(n, al, col + 1); } al.remove(al.size()-1); } } } public int totalNQueens(int n) { num=0; search(n,new LinkedList<Integer>(),1); return num; } }
思路3 :回溯法,只不过使用位移,速度超快,参考http://blog.csdn.net/kai_wei_zhang/article/details/8033194
public class Solution { // sum用来记录皇后放置成功的不同布局数;upperlim用来标记所有列都已经放置好了皇后。 static int sum = 0; static long upperlim = 1; void test(long l, long m, long n) { long pos; long p; if (l != upperlim) { // row,ld,rd进行“或”运算,求得所有可以放置皇后的列,对应位为0, // 然后再取反后“与”上全1的数,来求得当前所有可以放置皇后的位置,对应列改为1 // 也就是求取当前哪些列可以放置皇后 pos = upperlim & (~(l | m | n)); while (pos != 0) {// 0 -- 皇后没有地方可放,回溯 // 拷贝pos最右边为1的bit,其余bit置0 // 也就是取得可以放皇后的最右边的列 p = pos & -pos; //相当于p = pos & (~pos + 1) // 将pos最右边为1的bit清零 // 也就是为获取下一次的最右可用列使用做准备, // 程序将来会回溯到这个位置继续试探 pos -= p; // row + p,将当前列置1,表示记录这次皇后放置的列。 // (ld + p) << 1,标记当前皇后左边相邻的列不允许下一个皇后放置。 // (ld + p) >> 1,标记当前皇后右边相邻的列不允许下一个皇后放置。 // 此处的移位操作实际上是记录对角线上的限制,只是因为问题都化归 // 到一行网格上来解决,所以表示为列的限制就可以了。显然,随着移位 // 在每次选择列之前进行,原来N×N网格中某个已放置的皇后针对其对角线 // 上产生的限制都被记录下来了 test(l | p, (m | p) << 1, (n | p) >> 1); } } else ++sum; } public int totalNQueens(int n) { sum=0; upperlim = (1 << n) - 1; test(0, 0, 0); return sum; } }
时间: 2024-10-06 12:40:38