主题:我是新手!麻烦大家帮个忙!随机编考号的问题!
胖胖胖儿
[专家分:0] 发布于 2008-08-21 09:34:00
麻烦大家帮帮忙!我想给考生随机编考号,排考场!大家帮我编一下程!不胜感激!
已知报名号(bmh)、学校代码(xxdm),编程随机编排考号,从而填入考场。
Bmh : 报名号(已知,6位)
第1位:区代码(已给2个区,‘2’、‘3 ’)
第2位:科类代码(分别为1,5)
后4位:流水号(其中有不连续的地方)
Xxdm:学校代码(已知)
Ksh :考生号 (6位,需要编程填入)
编程有求:①第1、2位与bmh第1、2位相同,
②后四位:为流水号,但必须与bmh后四位不同,不能间断(即bmh互相挨着,ksh 是不挨着的,假如有1000人,ksh要利用0001,0002,0003...1000这些号打乱,随机排,不能断号)
③同一个区、同一个科类的要在一起编排。
④同一个学校不能前后挨着。一个考场30人,成7887座位。
Kc: 考场 (根据随机编排的ksh,需要编程填入),30人一考场。
需要操作的表我已上传,压缩文件!
最后更新于:2008-08-25 14:23:00
回复列表 (共11个回复)
沙发
jianzho [专家分:7560] 发布于 2008-08-21 12:04:00
read()
板凳
胖胖胖儿 [专家分:0] 发布于 2008-08-21 15:12:00
谢谢!
但我还是不会阿!
麻烦大家能告诉我多一点儿么!
3 楼
胖胖胖儿 [专家分:0] 发布于 2008-08-24 10:54:00
那位好人可以腾出一点宝贵时间,帮帮我吗!真的不胜感激!
4 楼
jinlonggao [专家分:17130] 发布于 2008-08-24 13:23:00
座位是这样排吗?
-------------------------------
8 23
7 9 * 24
6 10 * *
5 11 * *
4 12 * *
3 13 * *
2 * * *
1 15 16 30
--------------------------------
是否允许同一考场有不同区号和科目号的考生,即某一区号和科目号的考生排到最后时,剩余的考生不足30人时,是否要把另一区号或科目号的考生排进来?
考生号能否这样编排?即前第一位为区号,第二位为科目号,第三、四位为考场号,第五、六位为座位号?
5 楼
胖胖胖儿 [专家分:0] 发布于 2008-08-25 12:52:00
哈哈,太好了,终于有好心人帮我了!
座位号是
7 8 23 24
6 9 22 25
5 10 21 26
4 11 20 27
3 12 19 28
2 13 18 29
1 14 17 30
15 16
一个区、一个科类的排!坐不满时,另起考场!每一个科类后四位流水号都是从0001开始的!
考号后四位就是纯流水号,不包含考场号、座位号!考场号、座位号可以用后四位除以30算出来的!
6 楼
jinlonggao [专家分:17130] 发布于 2008-08-25 19:12:00
考场编号是否也要按区和科类号从01号开始?
7 楼
jinlonggao [专家分:17130] 发布于 2008-08-25 20:39:00
** 考场座位编排方式**
*-----------------------*
* 8 23 *
* 7 9 22 24 *
* 6 10 21 25 *
* 5 11 20 26 *
* 4 12 19 27 *
* 3 13 18 28 *
* 2 14 17 29 *
* 1 15 16 30 *
*-----------------------*
use <你的路径>\0203.dbf alias examcode
m.time0 =SECONDS()
SET SAFETY off
SELECT examcode
REPLACE ALL ksh WITH '',kc WITH ''
PUBLIC ARRAY axxdm(30)
SELECT qh,COUNT(qh) as kss,CEILING(COUNT(qh)/30) as kcs FROM ( SELECT left(bmh,2) as qh FROM examCode ) AA GROUP BY qh INTO CURSOR bmh1
SELECT bmh1
m.kczs = 0 && 考场总数
SCAN
m.qh = qh
m.kss = kss
m.kcs = kcs
SELECT examCode
SET FILTER TO LEFT(bmh,2) = m.qh AND EMPTY(ksh)
FOR i = 1 TO kcs
m.kch = PADL(ALLTRIM(STR(m.kczs + i)),3,'0')
m.xxdm = ' '
FOR j = 1 TO 30
COUNT TO nn
IF nn = 0
exit
endif
m.zwh = PADL(ALLTRIM(STR(j)),2,'0')
IF j = 1
SELECT TOP 2 xxdm,COUNT(*) as kss FROM examCode WHERE LEFT(bmh,2) = m.qh AND EMPTY(ksh) GROUP BY xxdm ORDER BY kss DESC INTO CURSOR xxdm1
SELECT xxdm1
GO 1
STORE xxdm TO axxdm(1),axxdm(8),axxdm(25)
IF RECCOUNT() > 1
GO 2
STORE xxdm TO axxdm(2),axxdm(9),axxdm(24)
endif
ENDIF
SELECT examcode
IF INLIST(j,1,2,8,9,24,25)
LOCATE FOR xxdm = axxdm(j) AND EMPTY(ksh)
IF MOD(INT(RAND()*10),2)=0 AND FOUND()
CONTINUE &&多一次查找,是为了增加排序的随机性
IF !FOUND()
LOCATE FOR xxdm = axxdm(j) AND EMPTY(ksh)
ENDIF
ENDIF
IF FOUND()
REPLACE ksh WITH m.kch + m.zwh, kc WITH m.kch
axxdm(j) =xxdm
loop
ENDIF
endif
IF BETWEEN(j,3,7) OR BETWEEN(j,10,23) OR BETWEEN(j,26,30)
LOCATE FOR xxdm = axxdm(j-2) AND EMPTY(ksh)
IF FOUND()
REPLACE ksh WITH m.kch + m.zwh, kc WITH m.kch
axxdm(j) =xxdm
loop
ENDIF
endif
m.counter = 0
DO WHILE .t.
m.xh = INT(RAND()*nn)
GO top
skip(m.xh)
IF BETWEEN(j,2,7) AND xxdm # axxdm(j-1);
OR BETWEEN(j,9,15) AND !INLIST(xxdm,axxdm(j-1),axxdm(j-(j-8)*2));
OR BETWEEN(j,16,23) AND !INLIST(xxdm,axxdm(j-1),axxdm(j-(j-16)*2-1));
OR BETWEEN(j,25,30) AND !INLIST(xxdm,axxdm(j-1),axxdm(j-(j-23)*2));
OR INLIST(j,1,8);
OR j=24 AND xxdm # axxdm(22)
REPLACE ksh WITH m.kch + m.zwh, kc WITH m.kch
axxdm(j) =xxdm
exit
ENDIF
m.counter =m.counter + 1
IF m.counter > 100 AND 30 - j > nn
REPLACE ALL ksh WITH '' FOR kc = m.kch
??CHR(7)
j = 0
exit
ENDIF
ENDDO
ENDFOR
ENDFOR
SET FILTER TO LEFT(bmh,2) = m.qh
INDEX on ksh TO myidx
BROWSE TITLE "这是按考场号和座位号编排的考生号,浏览完后关闭该窗口,让程序继续运行!"
REPLACE ALL ksh WITH PADL(alltr(str((VAL(LEFT(ksh,3))-m.kczs-1)*30+VAL(subs(ksh,4,2)))),4,'0')
REPLACE ALL ksh WITH m.qh + ksh
brow title '这是按区号、科目号和流水号编排的考生号,浏览完后关闭该窗口,让程序继续运行!'
m.kczs = m.kczs + m.kcs
SELECT bmh1
ENDSCAN
SELECT examcode
m.time1 = SECONDS()-m.time0
MESSAGEBOX(m.time1) &&用时统计
BROWSE
USE
SET SAFETY ON
return
--------------------------------------------------------------------------------
程序是按四楼的座位安排编写的,先贴出来供你参考,待后发按5楼座位安排改过的程序.
注意,在运行本程序前先打开你的数据表.
编了两个下午,完成到这程度,你先运行看,如果可以,并且你愿意,请给我买张电话充值卡,要100元的,然后把卡号及密号发给我,算是你的一点谢意,如不愿意,没关系,我同样会把后续的程序给你贴出来!
8 楼
胖胖胖儿 [专家分:0] 发布于 2008-08-26 10:56:00
我给你发短消息了,看见了么!
还有,这个我基本看不明白啊!
您是先随机编ksh,再按编好的ksh填入kc吗!思路应该是这样的!
还有考生数比如某一区的某一科类是100人,但bmh可能断了,尾号可能是105!但要求ksh是利用0001~0100这100个号打乱随机编排。
9 楼
jinlonggao [专家分:17130] 发布于 2008-08-26 16:53:00
下贴是我按你的座位布局排的考生编号,我发现你的座位布局更简单一些,要考虑前后左右不是一个学校的,只需考虑座位的奇偶数不同校就可以了.所以比我在七楼的排位更简单,但程序并不简单,因为,充分考虑到了随机性和每次排序的成功率.具体思路如下:
1. 计算不同区号和科目的考场数,通过一个查询语句实现;
2. 用设置筛选的办法逐一编排每个不同区科的全部考场;
3. 随机编排每个考场的座位号,既要考虑临座不同校,又要考虑把所有学校的考生排完,避免到最后剩下的全是一个学校的考生,所以,就要再设置一个查询,将当前未排座位的全部考生中人数最多的两个学校找出来,分别排给单号和双号,在排位的过程中,当单号或双号指定的学校排完后,就要再运行一次查询,找出当前未排位人数最多的两所学校,选其一重新指定给排完的单号或双号;
用locate for 语句定位的记录经常是某个学校排在最前面的一条记录,为了增加随机性,就要在定位到第一条记录后,再向下继续查找若干次(通过设置随机数实现).
4.按上面的算法,在排位时最先考虑的是人数最多的学校,人数最少的学校排在每个区科的最后几个考场,最前面若干个考场往往是人数最多的某两个学校,如若不这样就可能出现在最后几个考场无法按临座不同校的原则编排座位的问题.
5.考生号先是按考场号加座位号的格式编排,最后再按考场号与座位号,计算出四位流水号码;最终将区科号加在这四位流水号的前面.
在程序中,我把考场号统一编排,不知你是否要求按不同区科号重新起编,如果要求,那改起来相当简单.而且程序还能更简化.
时间关系,算法可能不是最优,所以较费时,在我新近购买的core2双核T5750笔记本上运行大概需要4到8分钟.
10 楼
jinlonggao [专家分:17130] 发布于 2008-08-26 17:13:00
** 考场座位编排方式**
*-----------------------*
* 7 8 23 24 *
* 6 9 22 25 *
* 5 10 21 26 *
* 4 11 20 27 *
* 3 12 19 28 *
* 2 13 18 29 *
* 1 14 17 30 *
* 15 16 *
*-----------------------*
Use <你的路径>\0203.dbf alias examcode
m.time0 =SECONDS() && 读取程序开始运行时的秒数
SET SAFETY off
PUBLIC ARRAY axxdm(2)
STORE ' ' TO axxdm(1),axxdm(2)
SELECT examcode && 选择考生信息表(0203.dbf)
REPLACE ALL ksh WITH '',kc WITH '' && 初始化数据表
*查询不同"区科"中考生人数及需要设置的考场数目
SELECT qh,COUNT(qh) as kss,CEILING(COUNT(qh)/30) as kcs FROM ( SELECT left(bmh,2) as qh FROM examCode ) AA GROUP BY qh INTO CURSOR bmh1
SELECT bmh1
m.kczs = 0 && 考场总数
SCAN
m.qh = qh && 区号和科目号
m.kcs = kcs && 考场数
SELECT examCode
SET FILTER TO LEFT(bmh,2) = m.qh AND EMPTY(ksh) && 设置筛选
FOR i = 1 TO kcs
m.kch = PADL(ALLTRIM(STR(m.kczs + i)),3,'0') && 不分区科,考场号连续编号
m.xxdm = ''
*统计目前未编座位号考生人数最多的两所学校的学校代码,以确定下一个考场需要优先考虑的两所学校
SELECT TOP 2 xxdm,COUNT(*) as kss FROM examCode WHERE LEFT(bmh,2) = m.qh AND EMPTY(ksh) GROUP BY xxdm ORDER BY kss DESC INTO CURSOR xxdm1
SELECT xxdm1
GO 1
axxdm(1) = xxdm
IF RECCOUNT() > 1
GO 2
axxdm(2) = xxdm
ENDIF
SELECT examcode
FOR j = 1 TO 30 && 为每个考场的每个座位编排考生
COUNT TO nn && 统计剩余的考生人数
IF nn = 0
EXIT && 如果剩余考生人数为零,则退出循环
endif
m.zwh = PADL(ALLTRIM(STR(j)),2,'0') && 生成字符型的座位号
COUNT TO m.nxxdm FOR xxdm =axxdm(2-MOD(j,2)) AND EMPTY(ksh) && 统计指定学校剩余考生人数
IF m.nxxdm = 0
SELECT TOP 2 xxdm,COUNT(*) as kss FROM examCode WHERE LEFT(bmh,2) = m.qh AND EMPTY(ksh) GROUP BY xxdm ORDER BY kss DESC INTO CURSOR xxdm1
SELECT xxdm1
GO 1
IF xxdm = axxdm(MOD(j,2)+1) AND RECCOUNT() = 2
GO 2
ENDIF
axxdm(2-MOD(j,2)) = xxdm
IF axxdm(2-MOD(j,2)) == axxdm(MOD(j,2)+1)
MESSAGEBOX('学校'+axxdm(MOD(j,2)+1)+'的人数太多了,没办法不紧邻着排!')
ENDIF
SELECT examcode
ENDIF
LOCATE FOR xxdm = axxdm(2-MOD(j,2)) AND EMPTY(ksh) && 定位到剩余考生人数最多的学校的考生
IF m.nxxdm > 2 && 如果考生人数多于两人,则进行随机查询,以增加编号的随机性
m.ncontinue = ceiling(RAND()*m.nxxdm)
m.ncontinue = IIF(m.ncontinue=m.nxxdm,m.ncontinue-1,m.ncontinue)
FOR k = 1 TO m.ncontinue
continue
ENDFOR
ENDIF
REPLACE ksh WITH m.kch + m.zwh, kc WITH m.kch
ENDFOR && 编排每一考场的座位号
ENDFOR && 编排同一区科的全部考场
SET FILTER TO LEFT(bmh,2) = m.qh
INDEX on ksh TO myidx
* BROWSE TITLE "这是按考场号和座位号编排的考生号,浏览完后关闭该窗口,让程序继续运行!"
REPLACE ALL ksh WITH PADL(alltr(str((VAL(LEFT(ksh,3))-m.kczs-1)*30+VAL(subs(ksh,4,2)))),4,'0')
REPLACE ALL ksh WITH m.qh + ksh
* brow title '这是按区号、科目号和流水号编排的考生号,浏览完后关闭该窗口,让程序继续运行!'
m.kczs = m.kczs + m.kcs
SELECT bmh1
ENDSCAN
SELECT examcode
m.time1 = SECONDS()-m.time0
MESSAGEBOX(m.time1) &&用时统计
BROWSE
USE
SET SAFETY ON
return
我来回复