问题描述:
n皇后问题是一个古老而著名的问题,由国际象棋
棋手马克斯·贝瑟尔于1848年提出:在n×n格的国际象棋上摆放
n个皇后,使其不能互相攻击,即:任意两个皇后都不能处于同
一行、同一列或同一斜线上,问有多少种摆法?一种摆法称为问
题的一个解
回溯法思想:
第一个棋子从第一行开始,按照列从小到大的顺序选择摆放的位
置;接下来从第二行按照可行的方案,从小到大的顺序摆放第二个棋
子;在第一和第二个棋子固定的情况下,再选择可行的位置在第三行
上摆放第三个棋子,以此类推。每一步的执行将使问题变成更小规模
的问题而向下递归。
如果在某一行没有找到不冲突位置,则需要
回溯到上一行
,以此
类推,直至找出全部正确解。
非递归回溯算法的实现:
void Queens(int n) //求解n皇后问题
{ int i=1; //i表示当前行,也表示放置第i个皇后
q[i]=0; //q[i]是当前列,每个新考虑的皇后初始位置置为0列
while (i>=1) //尚未回溯到头,循环
{ q[i]++; //原位置后移动一列
while (q[i]<=n && !place(i)) //试探一个位置(i,q[i])
q[i]++;
if (q[i]<=n) //为第i个皇后找到了一个合适位置(i,q[i])
{ if (i==n) //若放置了所有皇后,输出一个解
dispasolution(n);
else //皇后没有放置完
{ i++; //转向下一行,即开始下一个新皇后的放置
q[i]=0; //每个新考虑的皇后初始位置置为0列
}
}
else i--; //若第i个皇后找不到合适的位置,则回溯到上一个皇后
}
}
bool place(int i) //测试第i行的q[i]列上能否摆放皇后
{ int j=1;
if (i==1) return true;
while (j<i) //j=1~i-1是已放置了皇后的行
{ if ((q[j]==q[i]) || (abs(q[j]-q[i])==abs(j-i)))
//该皇后是否与以前皇后同列,位置(j,q[j])与(i,q[i])是否同对角线
return false;
j++;
}
return true;
}
5.3.2 n皇后问题
5.3.2
非递归回溯算法的实现:
void Queens(int n)
//
求解
n
皇后问题
{ int i=1;
//i
表示当前行
,
也表示放置第
i
个皇后
q[i]=0;
//q[i]
是当前列
,
每个新考虑的皇后初始位置置为
0
列
while (i>=1)
//
尚未回溯到头,循环
{ q[i]++;
//
原位置后移动一列
while (q[i]<=n && !
place
(i))
//
试探一个位置
(i,q[i])
q[i]++;
if (q[i]<=n)
//
为第
i
个皇后找到了一个合适位置
(i,q[i])
{ if (i==n)
//
若放置了所有皇后
,
输出一个解
dispasolution(n);
else
//
皇后没有放置完
{ i++;
//
转向下一行
,
即开始下一个新皇后的放置
q[i]=0;
//
每个新考虑的皇后初始位置置为
0
列
}
}
else i--;
//
若第
i
个皇后找不到合适的位置
,
则回溯到上一个皇后
}
}
bool place(int i)
//
测试第
i
行的
q[i]
列上能否摆放皇后
{ int j=1;
if (i==1) return true;
while (j<i)
//j=1
~
i-1
是已放置了皇后的行
{ if ((q[j]==q[i]) || (abs(q[j]-q[i])==abs(j-i)))
//
该皇后是否与以前皇后同列,位置
(j,q[j])
与
(i,q[i])
是否同对角线
return false;
j++;
}
return true;
}