我把两个表文件结构按前几楼说的要求整理过了,然后重新修改了代码,你有空时研究一下吧。
SET TALK OFF
SET SAFETY OFF
SET COMPATIBLE FOXPLUS
SET DECIMALS TO 15
CLEAR ALL
SELECT 1
USE 领导干部听课安排表 ALIAS 人员表
SELECT 2
USE 教学楼楼层使用状态 ALIAS 楼层表
=RAND(-1)
************************
* 先处理有指定需求的人 *
************************
**************************************************************
* 根据应尽量满足所有条件的原则,按条件数从多到少的顺序整理, *
* 安排人员时,按指定的条件数从多到少顺序逐一进行。
*
**************************************************************
SELECT DISTINCT 人员代码,教学楼备注,VAL(楼层备注) 楼层,节次备注,0 条件数 FROM 人员表 ;
WHERE !EMPTY(节次备注) OR !EMPTY(教学楼备注) OR !EMPTY(楼层备注) ;
INTO CURSOR T1 READWRITE
SELECT T1
T1_Fields=AFIELDS(T1_Stru)
SCAN
条件数量=3 &&初始条件数量都是3个
FOR AA=2 TO 4
IF EMPTY(&T1_Stru[AA,1]) THEN &&逐个检查条件
条件数量=条件数量-1 &&发现空条件就减去一个条件数
ENDIF
NEXT
REPLACE 条件数 WITH 条件数量
ENDSCAN
SELECT * FROM T1 ORDER BY 条件数 DESC INTO ARRAY 指定需求人员
指定需求人员数=ALEN(指定需求人员,1)
FOR AA=1 TO 指定需求人员数
SELECT 楼层表
可听课=.T.
DO CASE
CASE !EMPTY(指定需求人员[AA,2]) AND 指定需求人员[AA,3]>0 AND !EMPTY(指定需求人员[AA,4]) &&分配情况1:全部都有指定
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4] AND 使用状态='是'
CASE !EMPTY(指定需求人员[AA,2]) AND 指定需求人员[AA,3]>0 &&分配情况2:指定教学楼和楼层
SELECT 听课节次 FROM 楼层表 ;
WHERE 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
使用状态='是' ;
INTO ARRAY 可用节次
IF VARTYPE(可用节次)<>'U' THEN &&如果有可听课节次
IF ALEN(可用节次,1)>1 THEN
&&如果1~4节都可听
指定需求人员[AA,4]=IIF(INT(RAND()*2+1)=1,'12','34') &&就随机指定两节
ELSE
指定需求人员[AA,4]=可用节次[1,1]
ENDIF
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4]
RELEASE ALL LIKE 可用节次
ELSE
可听课=.F.
ENDIF
CASE !EMPTY(指定需求人员[AA,2]) AND !EMPTY(指定需求人员[AA,4]) &&分配情况3:指定教学楼和节次
SELECT 楼层 FROM 楼层表 ;
WHERE 教学楼名称==指定需求人员[AA,2] AND 听课节次==指定需求人员[AA,4] AND ;
使用状态='是' ;
INTO ARRAY 可用节次
IF VARTYPE(可用节次)<>'U' THEN &&如果有可听课节次
可听课地点数=ALEN(可用节次,1)
IF 可听课地点数>1 THEN
&&如果有多个地点可听
地点序号=INT(RAND()*可听课地点数+1)
指定需求人员[AA,3]=VAL(可用节次[地点序号,1]) &&随机指定楼层
ELSE
指定需求人员[AA,3]=VAL(可用节次[1,1])
ENDIF
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4]
RELEASE ALL LIKE 可用节次
ELSE
可听课=.F.
ENDIF
CASE 指定需求人员[AA,3]>0 AND !EMPTY(指定需求人员[AA,4]) &&分配情况4:指定楼层和节次
SELECT 教学楼名称 FROM 楼层表 ;
WHERE VAL(楼层)=指定需求人员[AA,3] AND 听课节次==指定需求人员[AA,4] AND ;
使用状态='是' ;
INTO ARRAY 可用节次
IF VARTYPE(可用节次)<>'U' THEN &&如果有可听课节次
可听课地点数=ALEN(可用节次,1)
IF 可听课地点数>1 THEN
&&如果有多个地点可听
地点序号=INT(RAND()*可听课地点数+1)
指定需求人员[AA,2]=可用节次[地点序号,1] &&随机指定教学楼
ELSE
指定需求人员[AA,2]=可用节次[1,1]
ENDIF
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4]
RELEASE ALL LIKE 可用节次
ELSE
可听课=.F.
ENDIF
CASE !EMPTY(指定需求人员[AA,2]) &&分配情况5:仅指定教学楼
SELECT 楼层,听课节次 FROM 楼层表 ;
WHERE 教学楼名称==指定需求人员[AA,2] AND 使用状态='是' ;
INTO ARRAY 可用节次
IF VARTYPE(可用节次)<>'U' THEN &&如果有可听课节次
可听课地点数=ALEN(可用节次,1)
IF 可听课地点数>1 THEN
&&如果有多个地点可听
地点序号=INT(RAND()*可听课地点数+1)
指定需求人员[AA,3]=VAL(可用节次[地点序号,1]) &&随机指定楼层
指定需求人员[AA,4]=可用节次[地点序号,2] &&随机指定节次
ELSE
指定需求人员[AA,3]=VAL(可用节次[1,1])
指定需求人员[AA,4]=可用节次[1,2]
ENDIF
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4]
RELEASE ALL LIKE 可用节次
ELSE
可听课=.F.
ENDIF
CASE 指定需求人员[AA,3]>0 &&分配情况6:仅指定楼层
SELECT 教学楼名称,听课节次 FROM 楼层表 ;
WHERE VAL(楼层)=指定需求人员[AA,3] AND 使用状态='是' ;
INTO ARRAY 可用节次
IF VARTYPE(可用节次)<>'U' THEN &&如果有可听课节次
可听课地点数=ALEN(可用节次,1)
IF 可听课地点数>1 THEN
&&如果有多个地点可听
地点序号=INT(RAND()*可听课地点数+1)
指定需求人员[AA,2]=可用节次[地点序号,1] &&随机指定教学楼
指定需求人员[AA,4]=可用节次[地点序号,2] &&随机指定节次
ELSE
指定需求人员[AA,2]=可用节次[1,1]
指定需求人员[AA,4]=可用节次[1,2]
ENDIF
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4]
RELEASE ALL LIKE 可用节次
ELSE
可听课=.F.
ENDIF
CASE !EMPTY(指定需求人员[AA,4]) &&分配情况7:仅指定节次
SELECT 教学楼名称,楼层 FROM 楼层表 ;
WHERE 听课节次==指定需求人员[AA,4] AND 使用状态='是' ;
INTO ARRAY 可用节次
IF VARTYPE(可用节次)<>'U' THEN &&如果有可听课节次
可听课地点数=ALEN(可用节次,1)
IF 可听课地点数>1 THEN
&&如果有多个地点可听
地点序号=INT(RAND()*可听课地点数+1)
指定需求人员[AA,2]=可用节次[地点序号,1] &&随机指定教学楼
指定需求人员[AA,3]=VAL(可用节次[地点序号,2]) &&随机指定楼层
ELSE
指定需求人员[AA,2]=可用节次[1,1]
指定需求人员[AA,3]=VAL(可用节次[1,2])
ENDIF
LOCATE FOR 教学楼名称==指定需求人员[AA,2] AND VAL(楼层)=指定需求人员[AA,3] AND ;
听课节次==指定需求人员[AA,4]
RELEASE ALL LIKE 可用节次
ELSE
可听课=.F.
ENDIF
ENDCASE
IF !FOUND() OR !可听课 THEN &&如果没找到相应教学楼或楼层
=MESSAGEBOX('没有找到教学楼 '+指定需求人员[AA,2]+' 或楼层 '+STR(指定需求人员[AA,3],2)+CHR(13)+CHR(13);
+'无法安排 '+指定需求人员[AA,1]+' 的听课地点。将随机分配...',0,"提醒")
ELSE
***************************************************
* 如果找到听课地点,先在人员表中填上相应的信息... *
***************************************************
SELECT 人员表
LOCATE FOR 人员代码==指定需求人员[AA,1]
REPLACE 教学楼 WITH 楼层表.教学楼名称,楼层 WITH 楼层表.楼层,听课节次 WITH 指定需求人员[AA,4] ;
FOR 人员代码==指定需求人员[AA,1]
****************************************
* 再在楼层表相应地点的节次状态中“否” *
****************************************
SELECT 楼层表
REPLACE 使用状态 WITH '否'
ENDIF
NEXT
************************
* 再处理无指定需求的人 *
************************
SELECT COUNT(DISTINCT 人员代码) 剩余人数 FROM 人员表 WHERE EMPTY(教学楼) INTO ARRAY 剩余人数
SELECT COUNT(楼层) 可听课数 FROM 楼层表 WHERE 使用状态='是' INTO ARRAY 可听课数
IF 剩余人数[1]<可听课数[1] THEN &&如果剩下的人员不够分配
=MESSAGEBOX('当前可分配听课人员数为 '+STR(剩余人数[1],3)+',可供听课数为 '+STR(可听课数[1],3)+CHR(13)+CHR(13) ;
+'还缺 '+STR(可听课数[1]-剩余人数[1],3)+' 条任务无法安排。请增加人员...',0,"提醒")
ELSE
**********************************************
* 取出可安排听课的无指定需求人员,并随机排列 *
**********************************************
SELECT 人员代码,RAND() FROM 人员表 WHERE EMPTY(教学楼) ORDER BY 2 INTO ARRAY 随机人员
************************
* 取出可安排听课的楼层 *
************************
SELECT 听课节次,教学楼名称,楼层 FROM 楼层表 WHERE 使用状态='是' INTO ARRAY 可听课楼层
********************************
* 开始安排各听课人员对应的楼层 *
********************************
FOR AA=1 TO 剩余人数[1]
SELECT 人员表
LOCATE FOR 人员代码==随机人员[AA,1] &&按随机数排好的顺序开始逐个查找定位
IF AA<=可听课数[1] THEN &&如果可听课数量还没有安排完
REPLACE 听课节次 WITH 可听课楼层[AA,1],教学楼 WITH 可听课楼层[AA,2],楼层 WITH 可听课楼层[AA,3]
SELECT 楼层表 &&然后在楼层表中将已分配掉的课程节次注销掉
LOCATE FOR 教学楼名称==可听课楼层[AA,2] AND VAL(楼层)=VAL(可听课楼层[AA,3]) AND 听课节次==可听课楼层[AA,1]
REPLACE 使用状态 WITH '否'
ELSE
EXIT
ENDIF
NEXT
ENDIF
SET TALK ON
SET SAFETY ON
SET DECIMALS TO 2
USE IN T1
RETURN
[此贴子已经被作者于2016-6-7 11:06编辑过]