回溯算法-8皇后问题
2012-07-31 19:53
323 查看
8皇后问题表述:在n×n格的棋盘上放置彼此不受攻击的n个皇后。按照国际象棋的规则,皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。n后问题等价于在n×n格的棋盘上放置n个皇后,任何2个皇后不放在同一行或同一列或同一斜线上。求不同的解的个数。
![](http://pic002.cnblogs.com/images/2010/153357/2010102423261586.jpg)
解向量:(x1, x2, … , xn)
显约束:xi = 1,2, … ,n
隐约束:
1)不同列:xi != xj
2)不处于同一正、反对角线:|i-j| != |x(i)-x(j)|
利用递归回溯和迭代回溯两种不同的方法实现:
[/code]
另外附上一种快速位运算,运算速度显著提高.
[/code]
移位运算:http://vipan.com/htdocs/bitwisehelp.html
![](http://pic002.cnblogs.com/images/2010/153357/2010102423261586.jpg)
解向量:(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
相关文章推荐
- 回溯算法之N皇后问题的求解
- 国际象棋“皇后”问题的回溯算法
- 回溯算法基础---皇后问题,骑士游历,迷宫求解
- 回溯算法—N皇后问题
- 回溯算法之N皇后问题
- 回溯(su)算法之N皇后问题
- 国际象棋“皇后”问题的回溯算法
- 〖編程·C++〗回溯算法:排列树 - N皇后问题
- 国际象棋“皇后”问题的回溯算法
- 国际象棋“皇后”问题的回溯算法
- 回溯经典算法之四皇后问题
- 国际象棋“皇后”问题的回溯算法
- 国际象棋“皇后”问题的回溯算法
- 回溯算法—n皇后问题
- 算法学习:回溯解决4皇后问题
- 回溯算法——解决n皇后问题
- 求 N 皇后问题回溯算法
- 软件设计师算法之回溯法--8皇后问题
- 回溯算法 8皇后问题的一种解法 适合初学者观察整个回溯的过程
- 国际象棋“皇后”问题的回溯算法