近六周的课程设计,编了一个四百行的汇编程序,编的过程很不顺利,遇到种种意想不到的困难,但最终能够实现,可谓欣喜若狂,这期间学到了好多好多,遇到问题怎么精下心来解决,同时对汇编的理解也更加深刻了。所谓TAP任务指派问题,简单来说我实现的是有六个人,有六项任务,没个人做每一项任务的所消耗的时间代价不同,有一个六阶参考矩阵代价表,然后将六个员工编号为123456,固定不变,接下来随机产生几种任务的排序方案,假设任务命名为ABCDEF,可能随机产生一种方案为EDCABF,这意思就是第一个人做E任务,第二个人做D任务依次下去,最后计算每一种方案的总代价,然后计算每一种方案的带价总和,然和输出最优(代价值最小)的那一种方案。
运行结果图:
附源码:
DATAS SEGMENT
str1 db 'reference array:','$'
str2 db 'feasible plans:','$'
str3 db 'How many plans do you want:(1-6) ','$'
str4 db 'The optimal plan:','$'
str5 db 'The order of the employees:',0dh,0ah,'123456','$'
str6 db 'The value of these several kinds of schemes:','$'
str7 db 'The cost of this plan is:','$'
array db 5,6,9,7,4,6,8,3,5,4,6,7,6,2,4,7,8,9,9,7,6,8,4,5,7,4,3,6,8,9,5,7,8,9,6,4
peo db 1,2,3,4,5,6
StrEnter db 0dh,0ah,'$' ;回车换行
n dw 1 ;用于显示数组为矩阵计数
temp db 2
sii dw ?
q db 0 ;用在计算代价值的子函数中
save db 0 ;用于保存al的值
best db 0 ;保存最优代价值
chushu db 6 ;用于显示数组为矩阵作为除数
count dw 0 ;产生随机串计数用的
buf db 96 dup(?) ;最多保存八种方案
buff db 36 dup(?) ;提取buf中有用的数字
yy db 8 dup(?) ;保存六种方案的代价值
OUTp db 0h ;作为为调用显示函数保存的临时变量
countr db 0 ;作为临时的和值保存
num db 1 ;记录最小的数是第几个
DATAS ENDS
STACKS SEGMENT
;此处输入堆栈段代码
STACKS ENDS
CODES SEGMENT
ASSUME CS:CODES,DS:DATAS,SS:STACKS
START:
MOV AX,DATAS
MOV DS,AX
;此处输入代码段代码
;显示“参考数组:”
lea dx,str1
mov ah,9
int 21h
;显示回车换行
call CRLF ;调用子程序
;**********************显示参考矩阵********************************************
push si
lea si,array
mov cx,36 ;cx是loop的参考值
j1:
mov dl,[si]
add dl,30h
mov ah,2 ;调用2号中断,显示单个值
int 21h
mov ax,n
div chushu
cmp ah,0
jnz tz
call CRLF
tz:
inc n
inc si
loop j1
pop si
call CRLF;调用一次回车换行
;*****************显示员工排列的顺序******************************************
lea dx,str5
mov ah,9
int 21h
call CRLF
;*****************显示“你要选择多少种方案:(1-8)”*************************
;----显示提示语---------------------------------------------------------------
lea dx,str3
mov ah,9
int 21h
call CRLF
;----输入选择-----------------------------------------------------------------
j2: mov ah,7
int 21h
cmp al,'6'
ja j2
cmp al,'1'
jb j2
mov dl,al
mov ah,2
int 21h
mov save,al ;因为下面si:步骤会更改al的值
call CRLF
;*****************显示“feasible plans:”**************************************
s1: lea dx,str2
mov ah,9
int 21h
call CRLF
;************************产生随机方案********************************************
mov al,save
sub al,30h ;减去30h变成数字
mov ah,0
lea di,buf ;取buf首地址
mov cx,ax
C0:
call Random
loop C0
lea dx,buf
mov ah,9
int 21h
call CRLF
;****************显示“这几种解决方案的代价值:”*******************************
lea dx,str6
mov ah,9
int 21h
;********************计算每一种解决方案的值***************************************
call CALCU ;可能将save的值改变了
call CRLF
;*****************显示“最优的那个方案以及其代价值”****************************
call CRLF
lea dx,str4
mov ah,9
int 21h
;******************计算得到最优的那个方案**************************************
call CRLF
;lea dx,Str7 ;显示这最小方案的代价
;mov ah,9
;int 21h
lea si,yy
call CALBEST
;*******************************************************************************
call over ;调用结束程序
;*******************************************************************************
;######################调用的子程序#############################################
;****回车换行*******************************************************************
CRLF PROC NEAR
lea dx,StrEnter
mov ah,9
int 21h
RET
CRLF ENDP
;****结束程序*******************************************************************
OVER PROC NEAR
MOV AH,4CH
INT 21H
RET
OVER ENDP
;******产生随机方案******************************************************************
;入口为 di,将di后的六位填充六个随机数
Random proc near
push cx
push si
mov sii,di
mov cx,6
L3:
push cx
L0:
xor ax,ax
out 43h,al
in al,40h
cmp al,1
jb L0
cmp al,6
ja L0
or al,40h
mov si,sii
mov [di],al
mov ax,di
cmp ax,si
jz L2
sub ax,si
mov cx,ax
L1:
mov ah,[si]
cmp ah,[di]
jz L0
inc si
loop L1
L2:
pop cx
inc di
loop L3
mov [di],0dh
inc di
mov [di],0ah
inc di
mov [di],'$'
pop si
pop cx
ret
Random endp
;****计算代价值*****************************************************************
;入口:peo db 6 buf db 96 array(参考数组) db save db (保存几个方案)
;出口:res dw 8(保存所有方案的代价值)
CALCU PROC NEAR ;g97
push si
push di ;<<
push bp
call CRLF
call CONVERTBUFTOBUFF ;将buf中的有用数据存到buff中
lea si,yy ;保存六种方案的代价值
mov q,0 ;大循环的判断条件 db
f0:;将指针指向缓冲区的头部
lea di,buff
mov ah,0 ;控制到buff中的第几个方案的头地址
mov al,q
mul chushu ;乘以6
add di,ax ;fla标记是将si和di指向两个头指针
mov ax,0
mov ch,0 ;小循环的判断条件
fl:
inc ax
push ax ;>>
dec ax
mul chushu ;(x-1)*6+y (chushu=6)
mov bl,[di]
mov bh,0
add ax,bx ;计算要参考代价表的第几个值存在ax中
lea bp,array ;参考代价表
dec ax ;自减一下,因为没从0开始
add bp,ax
mov dl,[bp] ;取参考表的值到dl
mov dh,0
add countr,dl ;和值不断增加
inc di
pop ax
inc ch
cmp ch,chushu ;判断是否循环了六次
JNE fl
mov dl,countr ;把一种方案的六次的值放到dl中然后赋给
mov [si],dl ;将计算的结果压到yy
mov dl,[si]
mov OUTp,dl
call OUTPut
inc si;*;
mov countr,0 ;和重新清0,重新计算下一个方案的结果值
;mov dl,[si]
;mov OUTp,dl;<
;call OUTPut ;输出显示
inc q
mov al,q
cmp al,save ;比较大循环和save的值 看看是否结束
JNE f0
pop bp
pop di
pop si
RET
CALCU ENDP
;***计算最小的那个代价值*******************************************************
;入口 res dw 8
;出口 best dw
CALBEST PROC NEAR
push si
mov bl,1 ;记录最小的这个代价值是yy中的第几个
mov cl,save ;控制循环几次
dec cl
mov ch,0
;mov dx,cx ;验证save是否正确
;add dx,30h
;mov ah,2
;int 21h
;;;;;;;;;;验证压入YY的值是否正确;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
mov dl,[si]
mov best,dl
cmp cx,0 ;如果save等于0,则不要比较直接跳转结束
jz q3
inc si
q1:
mov dl,[si]
;add dx,30h
;mov ah,2
;int 21h
inc bl ;记录是数组中的第几个,以便输出那个方案
cmp dl,best
jnb q2 ;大于或等于则跳转到q2
mov best,dl
mov num,bl
q2:
inc si ;si加一是字节,如果保存的是dw类型的就要加2
loop q1
;此时已经计算好了dl和最小的值,接下来时显示
q3:
mov dl,num ;第几个方案最小
add dl,30h
mov ah,2
int 21h
call CRLF
;依次输出这六个方案
;mov dl,num
;add dl,30h
;mov ah,2
;int 21h
mov dl,num
push di
lea di,buff
mov dh,0
dec dl
mov al,dl
mov ah,0
mul chushu
add di,ax
;显示最优方案的六个字母
mov cx,6
q10:
mov dl,[di]
add dl,40h
mov ah,2
int 21h
inc di
loop q10
pop di
call CRLF
;显示这最小方案的代价的提示语
lea dx,Str7
mov ah,9
int 21h
mov dl,best ;显示最小方案的代价值
mov OUTp,dl
call OUTPut
pop si
RET
CALBEST ENDP
;*****将buf中的值去掉回车换行存到buff***********************************************************
CONVERTBUFTOBUFF PROC NEAR
push si
sub save,30h
mov al,save
mov ah,0
mov bl,6
mul bl ;控制多少次循环
mov cx,ax
mov bx,0
lea si,buf
lea di,buff
q4: mov dl,[si]
sub dl,40h
mov [di],dl
inc si
inc di
inc bx
cmp bx,6
JNE q5
add si,2
mov bx,0
q5: loop q4
pop si
RET
CONVERTBUFTOBUFF ENDP
;******将一个字节型的OUTp输出显示**********************************************
OUTPut proc ;字节型的OUTp两位数的和
push si
lea si,temp
mov al,OUTp
mov cx,1
mov bl,10
CX1:
cmp al,10
jb CX2 ;小于跳转
sub ah,ah ;清0
div bl
mov [si],ah ;余数赋给
inc si
inc cx
sub ah,ah ;余数部分清0
jmp CX1
CX2:
mov [si],al ;商赋给
CX3:
mov dl,[si] ;商显示
add dl,30h
mov ah,2
int 21h
dec si ;自减1,然后显示余数
loop CX3; ;循环两次 将商和余数显示出来
mov dl,' '
int 21h
pop si
RET
OUTput endp
;******************************************************************************
CODES ENDS
END START