您的位置:首页 > 其它

回溯算法-8皇后问题

2012-07-31 19:53 323 查看
8皇后问题表述:在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。求不同的解的个数。



解向量:(x1, x2, … , xn)

显约束:xi = 1,2, … ,n

隐约束:

   1)不同列:xi != xj

   2)不处于同一正、反对角线:|i-j| != |x(i)-x(j)|

利用递归回溯和迭代回溯两种不同的方法实现:

[code] // 皇后问题等价于求所有满足条件的子集树


public class NQueueProblem {


 


private int[] yPos;


private int n;


private static int sum;


 


public NQueueProblem(int n) {


this.n = n;


init(n);


}


 


private void init(int n) {


yPos = new int
;


for (int i = 0; i < n; i++) {


yPos[i] = 0;


}


}


 


// 递归回溯方法进行求解


// 将皇后置于第t行


private void backtrack(int t) {


if (t == n) {


sum++;


//输出当前解


printSolution();


} else {


for (int j = 0; j < n; j++) {


yPos[t] = j; // 皇后放置在第t行j列


if (isPlace(t)) {


// 考虑第t+1行


backtrack(t + 1);


}


}


}


}


 


// 迭代回溯实现


// 采用树的非递归深度优先遍历算法,将回溯法表示为一个非递归迭代过程


private void iterativeBacktrack() {


int t = 0; //从第0行开始迭代


yPos[t] = -1;


while (t>=0) {


yPos[t] += 1; // 向右移一列


/* 向右移至出最右列或可以放置皇后的列 */


while ((yPos[t] <n) && !(isPlace(t))) {


yPos[t] += 1;


}


// 向右移未移出棋盘


if (yPos[t] < n)


{


// 已移至最后一行


if (t == n-1) {


   sum++;  


   printSolution();


} 


else {


/* 向下移一行 */


t++;


  yPos[t] = -1;


}


} 


else {


// 即yPos[t]>n, 迭代到最后一列仍无解,则回溯到前一行


t--;


}


}


}


 


private boolean isPlace(int t) {


for (int i = 0; i < t; i++) {


if ((Math.abs(i - t) == Math.abs(yPos[i] - yPos[t]))


|| (yPos[i] == yPos[t])) {


return false;


}


}


return true;


}


 


void printSolution() {


for (int i = 0; i < n; i++) {


System.out.print("[" + i + "," + yPos[i] + "]" + " ");


if (i == n - 1) {


System.out.println();


}


}


}


 


public static void main(String[] args) {


NQueueProblem queen = new NQueueProblem(8);


System.out.println("递归回溯结果");


queen.backtrack(0);


System.out.println("迭代回溯结果");


queen.iterativeBacktrack();




}


}

[/code]

另外附上一种快速位运算,运算速度显著提高.

[code] public class Queen_Fastest {


 


public static int sum = 0, upperlimit = 1;


 


//放皇后时,从右到左递归放(右边是低位,左边是高位)


/**


* 三个参数每一位代表一列,bit为1的位置不能放置皇后(与上面放置的皇后在45度角或垂直方向上有冲突)


* @param row 位为1的列说明上面某一行在此列己放置一个皇后


* @param ld 位为1的说明对应的左上角线己有皇后


* @param rd 位为1的说明对应的右上角线己有皇后


*/


public static void compute(int row, int ld, int rd) {




if (row != upperlimit) {


    int pos = upperlimit & ~(row | ld | rd);


    //对当前行所有可以放置皇后的地方放置一个皇后,然后进入下一行


    while (pos != 0)


{


   int p = pos & -pos;    //取得最右边可放置皇后的位置


   pos -= p;//在去掉这个位置,说明这个位置己以测试过


   //放置下一行的皇后,修改三个参数垂直与45度角上以前放置皇后点据的下一行的位置


   compute(row + p, (ld + p) << 1, (rd + p) >> 1);


}


 


} else //row所有列都为1,说明己成功得到一个方案


sum++;


}


 


 


public static void main(String[] args) {


Calendar start;


int n = 8;


if (args.length > 0)


    n = Integer.parseInt(args[0]);


start = Calendar.getInstance();


if ((n < 1) || (n > 32)) {


    System.out.println(" 只能计算1-32之间\n");


    return;


}


System.out.println(n + " 皇后\n");


upperlimit = (upperlimit << n) - 1;


compute(0, 0, 0);


System.out.println("共有" + sum + "种排列, 计算时间"


   + (Calendar.getInstance().getTimeInMillis() - start.getTimeInMillis()) + "毫秒 \n");


}


 


}

[/code]

移位运算:http://vipan.com/htdocs/bitwisehelp.html
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: