| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 2659 人关注过本帖
标题:很急!如何实现对任务项进行随机安排?
只看楼主 加入收藏
dengxsh
Rank: 2
等 级:论坛游民
帖 子:87
专家分:40
注 册:2013-2-26
结帖率:73.68%
收藏
已结贴  问题点数:10 回复次数:27 
很急!如何实现对任务项进行随机安排?
【需求】:
    当“巡视人员数≥巡视任务数”时,如何对楼层使用状态为“是”的任务随机安排巡视人员;当“巡视人员数<巡视任务数”时,弹出对话框提示“还缺*条任务无法安排,请增加人员!”。
——————————————
【规则】:
    1.每1条巡视任务需安排1个巡视人员。本附件中有人员63人,任务60条(12节为“是”的34项,34节26项),就是从63人中安排60人参加巡视任务,其余3人忽略不管。
    2.个别人员固定任务(如表中操作表中指定部分),然后对剩余任务进行随机安排。
随机安排.rar (3.11 KB)
搜索更多相关主题的帖子: 如何 
2016-06-02 12:52
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
我觉得这个题不错,不过操作表文件需要动点小手术。先让我在这里Mark一下,等弄出来了贴代码。
2016-06-02 14:52
dengxsh
Rank: 2
等 级:论坛游民
帖 子:87
专家分:40
注 册:2013-2-26
收藏
得分:0 
回复 2楼 taifu945
谢谢老师,期待您的帮助!
2016-06-02 15:52
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
答案有了啊:
首先,你得先把那个“操作表”略微改一下结构,把需求另外建立三个字段(见下图桔色框部分),这样就能把正常数据写进正常字段中了;
其次,我在你给的数据中略微扩展了一下,符合各种需求,比如:只需单楼层,教学楼和节次可随意;只需教学楼+楼层,而节次可随意等等各种组合;
再次,我在程序中加入了指定需求无法安排的处理。我的处理是:将无法处理需求的人员加入到随机分配人员中(见下图大红色框部分)。你也可将代码改成指定需求无法安排时,不作安排。
好了,下面就是代码了。我在代码中写了大量的注释,以便向你传达代码的思路,再有看不懂的可跟帖问我。
SET TALK OFF
SET SAFETY OFF
SET COMPATIBLE FOXPLUS
SET DECIMALS TO 15
CLEAR ALL

=RAND(-1)
SELECT 1
USE (操作表)领导干部听课安排表 ALIAS 人员表
SELECT 2
USE 教学楼楼层使用状态 ALIAS 楼层表

************************
* 先处理有指定需求的人 *
************************
SELECT DISTINCT ALLTRIM(人员代码),"" 教学楼信息预留,0 楼层信息预留,"" 节次信息预留 ;
   FROM 人员表 ;
   WHERE !EMPTY(ALLTRIM(节次备注)) OR !EMPTY(ALLTRIM(教学楼备注)) OR ;
         !EMPTY(ALLTRIM(楼层备注)) ;
   INTO ARRAY 指定需求人员

指定需求人员数=ALEN(指定需求人员,1)
FOR AA=1 TO 指定需求人员数
   当前人员代码=ALLTRIM(指定需求人员[AA,1])
   SELECT ALLTRIM(教学楼备注), ALLTRIM(楼层备注), ALLTRIM(节次备注) FROM 人员表 ;
      WHERE ALLTRIM(人员代码)==当前人员代码 ;
      INTO ARRAY 人员信息
   FOR BB=1 TO 3
      IF !EMPTY(人员信息[BB]) THEN
         起始双引号位置=ATCC('“',人员信息[BB])
         DO CASE
            CASE BB=1 &&如果是教学楼信息,就取备注双引号里的全部内容
               终止双引号位置=ATCC('”',人员信息[BB])
               指定需求人员[AA,2]=SUBSTRC(人员信息[BB],起始双引号位置+1,终止双引号位置-起始双引号位置-1)
            CASE BB=2 &&如果是楼层信息,就转换成数字,方便后面对比
               指定需求人员[AA,3]=VAL(SUBSTRC(人员信息[BB],起始双引号位置+1,2))
            CASE BB=3 &&如果是节次信息,只取节次的数字
               指定需求人员[AA,4]=SUBSTRC(人员信息[BB],起始双引号位置+1,2)
         ENDCASE
      ENDIF
   NEXT
   SELECT 楼层表
   DO CASE
      CASE 指定需求人员[AA,3]=0 AND EMPTY(指定需求人员[AA,4]) &&如果仅指定教学楼
         LOCATE FOR ALLTRIM(教学楼名称)==指定需求人员[AA,2] AND ;
                    (ALLTRIM(状态(12))='是' OR ALLTRIM(状态(34))='是')
         DO CASE
            CASE ALLTRIM(状态(12))='是' AND ALLTRIM(状态(34))='是' &&如果1~4节都可听
               指定需求人员[AA,4]=IIF(INT(RAND()*2+1)=1,'12','34') &&就随机指定两节         
            CASE ALLTRIM(状态(12))='是' &&如果只有1、2节可听
               指定需求人员[AA,4]='12'
            CASE ALLTRIM(状态(34))='是' &&如果只有3、4节可听
               指定需求人员[AA,4]='34'
         ENDCASE
      CASE EMPTY(指定需求人员[AA,2]) AND EMPTY(指定需求人员[AA,4]) &&如果仅指定楼层
         LOCATE FOR VAL(楼层)==指定需求人员[AA,3] AND ;
                    (ALLTRIM(状态(12))='是' OR ALLTRIM(状态(34))='是')
         DO CASE
            CASE ALLTRIM(状态(12))='是' AND ALLTRIM(状态(34))='是' &&如果1~4节都可听
               指定需求人员[AA,4]=IIF(INT(RAND()*2+1)=1,'12','34') &&就随机指定两节         
            CASE ALLTRIM(状态(12))='是' &&如果只有1、2节可听
               指定需求人员[AA,4]='12'
            CASE ALLTRIM(状态(34))='是' &&如果只有3、4节可听
               指定需求人员[AA,4]='34'
         ENDCASE
      CASE EMPTY(指定需求人员[AA,2]) AND 指定需求人员[AA,3]=0 &&如果仅指定节次
         IF 指定需求人员[AA,4]='12' THEN
            LOCATE FOR ALLTRIM(状态(12))='是'
         ELSE
            LOCATE FOR ALLTRIM(状态(34))='是'
         ENDIF
      CASE EMPTY(指定需求人员[AA,4]) &&如果指定了教学楼和楼层
         LOCATE FOR ALLTRIM(教学楼名称)==指定需求人员[AA,2] AND VAL(楼层)==指定需求人员[AA,3] AND ;
                    (ALLTRIM(状态(12))='是' OR ALLTRIM(状态(34))='是')
         DO CASE
            CASE ALLTRIM(状态(12))='是' AND ALLTRIM(状态(34))='是' &&如果1~4节都可听
               指定需求人员[AA,4]=IIF(INT(RAND()*2+1)=1,'12','34') &&就随机指定两节         
            CASE ALLTRIM(状态(12))='是' &&如果只有1、2节可听
               指定需求人员[AA,4]='12'
            CASE ALLTRIM(状态(34))='是' &&如果只有3、4节可听
               指定需求人员[AA,4]='34'
         ENDCASE
      CASE 指定需求人员[AA,3]=0 &&如果指定了教学楼和节次
         IF 指定需求人员[AA,4]='12' THEN &&1、2节
            LOCATE FOR ALLTRIM(教学楼名称)==指定需求人员[AA,2] AND ALLTRIM(状态(12))='是'
         ELSE &&3、4节
            LOCATE FOR ALLTRIM(教学楼名称)==指定需求人员[AA,2] AND ALLTRIM(状态(34))='是'
         ENDIF
      CASE EMPTY(指定需求人员[AA,2]) &&如果指定了楼层和节次
         IF 指定需求人员[AA,4]='12' THEN &&1、2节
            LOCATE FOR VAL(楼层)==指定需求人员[AA,3] AND ALLTRIM(状态(12))='是'
         ELSE &&3、4节
            LOCATE FOR VAL(楼层)==指定需求人员[AA,3] AND ALLTRIM(状态(34))='是'
         ENDIF
      OTHERWISE &&如果全部都有指定
         IF 指定需求人员[AA,4]='12' THEN &&1、2节
            LOCATE FOR ALLTRIM(教学楼名称)==指定需求人员[AA,2] AND VAL(楼层)==指定需求人员[AA,3] AND ;
                       ALLTRIM(状态(12))='是'
         ELSE &&3、4节
            LOCATE FOR ALLTRIM(教学楼名称)==指定需求人员[AA,2] AND VAL(楼层)==指定需求人员[AA,3] AND ;
                       ALLTRIM(状态(34))='是'
         ENDIF
   ENDCASE
   IF !FOUND() THEN &&如果没找到相应教学楼或楼层
      =MESSAGEBOX('没有找到教学楼 '+指定需求人员[AA,2]+' 或楼层 '+STR(指定需求人员[AA,3],2)+CHR(13)+CHR(13);
                  +'无法安排 '+当前人员代码+' 的听课地点。请点击确定继续...',0,"提醒")
   ELSE
      ***************************************************
      * 如果找到听课地点,先在人员表中填上相应的信息... *
      ***************************************************
      SELECT 人员表
      LOCATE FOR ALLTRIM(人员代码)==当前人员代码
      REPLACE 教学楼 WITH ALLTRIM(楼层表.教学楼名称),楼层 WITH ALLTRIM(楼层表.楼层), ;
              听课节次 WITH 指定需求人员[AA,4] FOR ALLTRIM(人员代码)==当前人员代码
      ****************************************
      * 再在楼层表相应地点的节次状态中“否” *
      ****************************************
      SELECT 楼层表
      IF 指定需求人员[AA,4]='12' THEN &&1、2节
         REPLACE 状态(12) WITH '否'
      ELSE &&3、4节
         REPLACE 状态(34) WITH '否'
      ENDIF
   ENDIF
NEXT

************************
* 再处理无指定需求的人 *
************************
SELECT COUNT(DISTINCT 人员代码) 剩余人数 FROM 人员表 WHERE EMPTY(ALLTRIM(教学楼)) INTO ARRAY 剩余人数
SELECT COUNT(楼层) 一二节可听数 FROM 楼层表 WHERE ALLTRIM(状态(12))='是' INTO ARRAY 一二节可听数
SELECT COUNT(楼层) 三四节可听数 FROM 楼层表 WHERE ALLTRIM(状态(34))='是' INTO ARRAY 三四节可听数
IF 剩余人数[1]<一二节可听数[1]+三四节可听数[1] THEN &&如果剩下的人员不够分配
   =MESSAGEBOX('当前可分配听课人员数为 '+STR(剩余人数[1],3)+',可供听课数为 '+STR(一二节可听数[1]+三四节可听数[1],3) ;
               +CHR(13)+CHR(13)+'还缺 '+STR(一二节可听数[1]+三四节可听数[1]-剩余人数[1],3)+ ;
               ' 条任务无法安排。请增加人员...',0,"提醒")
ELSE
   **********************************
   * 取出可安排听课的无指定需求人员 *
   **********************************
   SELECT ALLTRIM(人员代码),RAND() FROM 人员表 WHERE EMPTY(ALLTRIM(教学楼)) ORDER BY 2 INTO ARRAY 随机人员 &&剩下人员按随机数升序排列
   
   ******************************
   * 取出各节次可安排听课的楼层 *
   ******************************
   SELECT '12' 节次,ALLTRIM(教学楼名称),ALLTRIM(楼层) FROM 楼层表 WHERE ALLTRIM(状态(12))='是' INTO ARRAY 一二节可听楼层
   SELECT '34' 节次,ALLTRIM(教学楼名称),ALLTRIM(楼层) FROM 楼层表 WHERE ALLTRIM(状态(34))='是' INTO ARRAY 三四节可听楼层
   
   ********************************
   * 开始安排各听课人员对应的楼层 *
   ********************************
   一二节可听课数量=ALEN(一二节可听楼层,1)
   三四节可听课数量=ALEN(三四节可听楼层,1)
   FOR AA=1 TO ALEN(随机人员,1)
      SELECT 人员表
      LOCATE FOR ALLTRIM(人员代码)==ALLTRIM(随机人员[AA,1]) &&按随机数排好的顺序开始逐个查找定位
      IF AA<=一二节可听课数量 THEN &&如果目前已安排听课的数量还在第1、2节的总数内,就分配第1、2节
         REPLACE 听课节次 WITH 一二节可听楼层[AA,1],教学楼 WITH ALLTRIM(一二节可听楼层[AA,2]), ;
                 楼层 WITH ALLTRIM(一二节可听楼层[AA,3])
         SELECT 楼层表 &&然后在楼层表中将已分配掉的课程节次注销掉
         LOCATE FOR ALLTRIM(教学楼名称)==ALLTRIM(一二节可听楼层[AA,2]) AND ;
                    VAL(楼层)=VAL(一二节可听楼层[AA,3])
         REPLACE 状态(12) WITH '否'
      ELSE &&AA超出了第1、2节的总数,就开始安排第3、4节
         IF AA<=一二节可听课数量+三四节可听课数量 THEN &&如果可听课数量未分配完,则继续分配。
            REPLACE 听课节次 WITH 三四节可听楼层[AA-一二节可听课数量,1], ;
                    教学楼 WITH ALLTRIM(三四节可听楼层[AA-一二节可听课数量,2]), ;
                    楼层 WITH ALLTRIM(三四节可听楼层[AA-一二节可听课数量,3])
            SELECT 楼层表 &&然后在楼层表中将已分配掉的课程节次注销掉
            LOCATE FOR ALLTRIM(教学楼名称)==ALLTRIM(三四节可听楼层[AA-一二节可听课数量,2]) AND ;
                       VAL(楼层)=VAL(三四节可听楼层[AA-一二节可听课数量,3])
            REPLACE 状态(34) WITH '否'
         ENDIF
      ENDIF
   NEXT

ENDIF

SET TALK ON
SET SAFETY ON
SET DECIMALS TO 2
RETURN

图片附件: 游客没有浏览图片的权限,请 登录注册

2016-06-02 22:46
dengxsh
Rank: 2
等 级:论坛游民
帖 子:87
专家分:40
注 册:2013-2-26
收藏
得分:0 
回复 4楼 taifu945
老师,非常感谢您的帮助!烦请将最终附件回发一下,必须学习您的思想……
2016-06-02 23:33
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
以下是引用dengxsh在2016-6-2 23:33:59的发言:

老师,非常感谢您的帮助!烦请将最终附件回发一下,必须学习您的思想……

随机安排听课人员.rar (2.34 KB)


这个压缩包里只有PRG文件。另外,我想说的是,你这个楼层表的结构还是有点问题,虽然我写的代码是按你现在的表结构来的,但还是希望你改成这样:

教学楼名称   教学楼代码   楼层   节次   状态
教1            AA          01     12     
教1            AA          01     34     
教1            AA          03     12     
教1            AA          03     34     
... ...

这样才符合数据表的“原始”状态。你现在的结构其实相当于是统计后的“二次”数据了,虽然在日常这种结构用得多,但它不是“原始”结构。而且从写代码的方便性来说,你现在的这种结构也不如我建议的那种方便。我写代码时感觉最复杂的就是判断哪个节次可听课,这完全是表结构设计得不合理造成的。
2016-06-03 09:01
taifu945
Rank: 12Rank: 12Rank: 12
等 级:贵宾
威 望:80
帖 子:1545
专家分:3298
注 册:2012-7-6
收藏
得分:0 
对了,还有,指定需求时其实只要写关键的就行了,根本不需要写那么详细,比如:节次备注:12(或34);教学楼备注:教1、轻化楼;楼层备注:01、02、...,这样也可以简化代码。
2016-06-03 09:17
dengxsh
Rank: 2
等 级:论坛游民
帖 子:87
专家分:40
注 册:2013-2-26
收藏
得分:0 
回复 7楼 taifu945
老师,您说的对。我在表中的表述很详细,目的是强调指定任务,实际操作表应该如您那样简化的
2016-06-03 09:33
antony521
Rank: 3Rank: 3
等 级:论坛游侠
威 望:1
帖 子:170
专家分:175
注 册:2009-8-20
收藏
得分:0 
回复 6楼 taifu945
请按正确的表结构再来一段代码,以便其他人借鉴.谢谢!
2016-06-03 09:36
dengxsh
Rank: 2
等 级:论坛游民
帖 子:87
专家分:40
注 册:2013-2-26
收藏
得分:0 
回复 6楼 taifu945
老师建议修改后的教学楼楼层使用状态表更加清晰,那代码是否需要修改?恳请予以帮助!
2016-06-03 09:40
快速回复:很急!如何实现对任务项进行随机安排?
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.037508 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved