回溯法解决八皇后问题
八皇后问题是以国际象棋为背景的问题:有八个皇后(可以当成八个棋子),如何在 8*8 的棋盘中放置八个皇后,
使得任意两个皇后都不在同一条横线、纵线或者斜线上。
八皇后问题是使用回溯法解决的典型案例。算法的解决思路是:
1.从棋盘的第一行开始,从第一个位置开始,依次判断当前位置是否能够放置皇后,判断的依据为:
同该行之前的所有行中皇后的所在位置进行比较,如果在同一列,或者在同一条斜线上
(斜线有两条,为正方形的两个对角线),都不符合要求,继续检验后序的位置。
2.如果该行所有位置都不符合要求,则回溯到前一行,改变皇后的位置,继续试探。
3.如果试探到最后一行,所有皇后摆放完毕,则直接打印出 8*8 的棋盘。最后一定要记得将棋盘恢复原样,避免影响下一次摆放。
#include <stdio.h>
int Queenes[8]={0},Counts=0;
int Check(int line,int list){
//遍历该行之前的所有行
for (int index=0; index<line; index++) {
//挨个取出前面行中皇后所在位置的列坐标
int data=Queenes[index];
//如果在同一列,该位置不能放
if (list==data) {
return 0;
}
//如果当前位置的斜上方有皇后,在一条斜线上,也不行
if ((index+data)==(line+list)) {
return 0;
}
//如果当前位置的斜下方有皇后,在一条斜线上,也不行
if ((index-data)==(line-list)) {
return 0;
}
}
//如果以上情况都不是,当前位置就可以放皇后
return 1;
}
//输出语句
void print()
{
for (int line = 0; line < 8; line++)
{
int list;
for (list = 0; list < Queenes[line]; list++)
printf("0");
printf("#");
for (list = Queenes[line] + 1; list < 8; list++){
printf("0");
}
printf("\n");
}
printf("================\n");
}
void eight_queen(int line){
//在数组中为0-7列
for (int list=0; list<8; list++) {
//对于固定的行列,检查是否和之前的皇后位置冲突
if (Check(line, list)) {
//不冲突,以行为下标的数组位置记录列数
Queenes[line]=list;
//如果最后一样也不冲突,证明为一个正确的摆法
if (line==7) {
//统计摆法的Counts加1
Counts++;
//输出这个摆法
print();
//每次成功,都要将数组重归为0
Queenes[line]=0;
return;
}
//继续判断下一样皇后的摆法,递归
eight_queen(line+1);
//不管成功失败,该位置都要重新归0,以便重复使用。
Queenes[line]=0;
}
}
}
int main() {
//调用回溯函数,参数0表示从棋盘的第一行开始判断
eight_queen(0);
printf("摆放的方式有%d种",Counts);
return 0;
}
汇编代码
INCLUDE Irvine32.inc
.data
Queens dd 8 dup(0)
Count dd 0
msg db 'The number of the way setting is:',0
sep db '===============',0
eight dd 8
seven dd 7
.code
main PROC
mov eax,0
push eax
call eight_queen
lea edx,msg
call writestring
mov eax,Count
call writedec
call crlf
; call print
exit
main ENDP
eight_queen PROC
push ebp
mov ebp,esp
pushad
mov esi,[ebp+8] ;esi:line
mov edi,0 ;edi:list
; mov eax,esi
; call writedec
; call crlf
for_0:
cmp edi,eight
jge final
push edi
push esi
call Check
cmp eax,1
jne for_0_end
mov edx,offset Queens ;edx:Queens
mov [edx+esi*4],edi
cmp esi,seven
; mov eax,edi
; call writedec
; call crlf
jne next
inc Count
call print
mov eax,0
mov edx,offset Queens
mov [edx+esi*4],eax
jmp final
next:
mov eax,esi
add eax,1
push eax
call eight_queen
mov edx,offset Queens
mov eax,0
mov [edx+esi*4],eax
for_0_end:
inc edi
jmp for_0
final:
popad
pop ebp
ret 4
eight_queen ENDP
Check PROC
push ebp
mov ebp,esp
sub esp,4
pushad
mov ecx,[ebp+8] ;ecx:line
mov edx,[ebp+12] ;edx:list
mov esi,0 ;esi:index
for_0:
cmp esi,ecx
jge ret1
mov ebx,offset Queens ;ebx:Queens
mov edi,[ebx+esi*4] ;edi:data
cmp edx,edi
je ret0
; mov ebx,offset Queens
mov edi,esi
add edi,[ebx+esi*4]
sub edi,ecx
sub edi,edx
cmp edi,0
je ret0
; mov ebx,offset Queens
mov edi,esi
sub edi,[ebx+esi*4]
sub edi,ecx
add edi,edx
cmp edi,0
je ret0
for_0_end:
inc esi
jmp for_0
ret1:
mov eax,1
mov [ebp-4],eax
jmp final
ret0:
mov eax,0
mov [ebp-4],eax
jmp final
final:
popad
mov eax,[ebp-4]
add esp,4
pop ebp
ret 8
Check ENDP
print PROC
push ebp
mov ebp,esp
pushad
mov esi,0 ;esi:line
for_0:
cmp esi,eight
jge final
mov edi,0 ;edi:list
for_1:
mov edx,offset Queens ;edx:Queens
cmp edi,[edx+esi*4]
jge next
mov eax,0
call writedec
for_1_end:
inc edi
jmp for_1
next:
mov al,'#'
call writechar
mov edx,offset Queens ;edx:Queens
mov edi,[edx+esi*4]
inc edi
for_2:
cmp edi,eight
jge for_0_end
mov eax,0
call writedec
for_2_end:
inc edi
jmp for_2
for_0_end:
call crlf
inc esi
jmp for_0
final:
lea edx,sep
call writestring
call crlf
popad
pop ebp
ret
print ENDP
END main