苦心找了个用汇编写的,::
;程序功能:用深度优先搜索法解决八皇后问题并打印结果.
;列数行数分别用1-8标记.所以八皇后的位置申请了9个
;调试感慨:汇编调试实在麻烦,不像C中在任何地方加个printf就可以知道
;哪错了.跳来跳去的,不知哪里死循环了,实在不好调试.
.model small,stdcall
;由于皇后位置都是一位数,所以加上30H后作字符打印出.
printResult macro
local again,print,first
push si ;不能改变它的值.
mov ah,02h ;输出状态不变.
mov cx,2 ;对称的结果,所以打两个结果.
again:
mov si,1
print:
mov dl,queen[si]
cmp cx,2
je first
mov bl,9
sub bl,dl
mov dl,bl
first:
add dl,30h
int 21h
inc si
cmp si,9 ;到第9个就是说打完了.
jnz print
mov dl,' ' ;输出两个空格,为好看.
int 21h
int 21h
loop again
pop si
endm
.data
;改来改去,何必那么小气呢?用9个多方便,就一个字节,不必这么小气!
queen db 9 dup(0)
used db 9 dup(0)
Nresult dw 0 ;结果的个数.
prompt db "The positions are:",0ah,0dh,'$'
over db 0ah,0dh,"The number of the result is $"
.code
;函数功能:把存在ax寄存器里的二进制数用十进制打印出来.
printaxd proc near
mov bx,10000d ;二个字节的数最大就3万多.
mov ch,0 ;还没出现第一个要打印的数(最高位的非0不需要打印)
mov cl,5 ;最多有五位,所以一共除五次.
mov si,ax ;哈哈,寄存器太聪明了.
go:
mov ax,si
mov dx,0 ;既然是除法,就要保证高位的绝对值最小.
div bx
dec cl ;除一次就减一次.
mov di,ax ;除完就把商移走,位置让出来给bx/10
mov si,dx ;保证余数.
;实现bx/10.
mov ax,bx
mov bx,10 ;记住乘除法运算不能用立即数.
mov dx,0 ; 实际上dl的最大值也就是9小于10,但为了保险和习惯,还是用这一句.
div bx
mov bx,ax
mov ax,di
cmp cl,0 ;如果到最后一位了,无论是0还是不为0,都要打印了.
jz next
or ch,al
jz go
next:
mov ch,1 ;有打印的了
mov dl,al
add dl,30h
mov ah,02h
int 21h
cmp cl,0
jnz go
ret ; This line cann't be forgotten.
printaxd endp
main proc far
mov ax,@data
mov ds,ax
mov es,ax
mov dx,offset prompt
mov ah,09h
int 21h
mov si,1 ;当然是从第一列开始.
go:
inc queen[si] ;当前列向下走一步.
;测试是否走出8*8的格子了
cmp queen[si],9
jnz stay
;刚好踏出格子,就把当前列置0,把上一列所在行置空,然后继续go.
mov queen[si],0
dec si
;取消所占的行.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
mov used[di],0
;是否完成搜索.
cmp si,1
jnz go
;调试记语:为什么为5时不退出呢?改成4后结果居然对了.最后一个疑问了!
;对!原来如此!退出是要在queen[1]为5时,当4变成5时,这个增加的过程
;在go的第一句,也就是说此时还为4.
;于是退出条件就是当此时第一列为4而又要向前址走一步时根据对称性
;就要退出了.
cmp queen[si],4 ;利用对称性,如果第一列算到5行,就不用算了.
je exit
jmp go
stay:
;留在方格内,那么就剩下是否满足不在同一行同一斜行的问题了.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
cmp used[di],1 ;如果为1就说明当前列的当前行已使用.
je go
;循环检查是否有在同一斜行的皇后.
mov di,si
dec di ; bx指向与当前列比较的列.
check:
cmp di,0
je checkover
mov dx,si ;dx装着当前列与检测列的差.,差最大不过7,所以也可以说是装在dl中.
sub dx,di
mov al,queen[si]
;al放两列的行之差.
sub al,queen[di]
cmp al,dl ;相等或相反就是在同一斜行.
je go
neg al ;求负数.
cmp al,dl
je go
dec di
jmp check
checkover:
;好,现在可以留下来了.
cmp si,8
jz result
;如果不是最后一列.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
mov used[di],1 ;留下来这一行就占住了.
inc si
jmp go
result: ;好,一个结果出来了,根据对称,实际出来两个结果.
add Nresult,2
printResult
mov queen[si],0
dec si
;这四行初为设计上的漏洞,想了老半天.
mov al,queen[si] ;不知何以不能用movzx di,queen[si]
cbw
mov di,ax
mov used[di],0
jmp go
exit:
mov dx,offset over
mov ah,09h
int 21h
mov ax,Nresult
call printaxd
mov ah,01h ; to pause
int 21h
mov ah,4ch
int 21h
main endp
end main
本文来自CSDN博客,转载请标明出处:http://blog.