java random随机派位_学生积分派位算法研究

场景描述

假设条件

1、schoolCount = 20学校志愿

2、placeCount = 2000个学位

3、personCount = 4000个学生报名

4、按照积分从高到低录取

5、接受调剂的则由系统调剂,不接受调剂的落选

6、选中误差<= 20%,即 2000 * 20% = 400 属于personCount - placeCount

7、设定可报志愿为N个

问题:当N为多少时,分数从高到低的前placeCount个学生中落选比例小于20%,并处于基本稳定状态

建模分析

志愿命中概率因素有5个

1、可填报的志愿数

2、是否接受调剂

3、学生的分数

4、填报志愿的顺序

5、各个学校的招收人数

1)接受调剂

1、当前N=placeCount都接受调剂时, 都可以上

2、当前N=placeCount部分不接受调剂时,则可能存在高分落选的学生

2)

1、当N = placeCount, 则

a)当前placeCount学生都全部填写20个志愿时,则积分前placeCount名的学生都可以上

b)当前2000名的学生中部分人填写志愿错误或未全部填写,则可能存在部分人落选,后面的2000名学生存在很小的机会

2、当N < 20,则

a)当前2000名学生的每个人都接受调剂时,则积分前2000名的学生都可以上,后面2000名学生没有任何概率机会

b)当前2000名学生的部分不调剂,则积分前2000名的学生则可能部分不能上

分析结果:

分数高的学生落选跟志愿数N没有决定关系,跟填报的学校顺序有关,跟是否接受调剂有关,若接受调剂,按照分数的高低,高分的学生必然优先上

志愿数N跟学生对多个学校组合优先有关,同时只有在不选择调剂的情况下,N的值越大(即学生可填写的志愿越多)分数高的学生越能保证上线,即当N=schoolCount时相当于接受调剂,但调剂的学校顺序未必与学生的设定的学校顺序一致

数据建表

/*学生表*/

CREATE TABLE [bm_person](

[personId] [int] NOT NULL,

[personNo] [varchar](50) NULL, /*学生号*/

[personName] [varchar](50) NULL,/*学生名称*/

[point] [int] NULL,/*学生分数*/

[schoolId] [int] NULL,/*被分配的学校*/

[isAdjust] [int] NULL,/*是否调剂*/

[isLose] [int] NULL/*是否高分落选*/

)

go

/*产生随机数表,用于初始化使用*/

CREATE TABLE [bm_random](

[id] [int] NOT NULL,

[random] [int] NULL,

[isUsed] [int] NULL

)

go

/*报考学校*/

CREATE TABLE [bm_school](

[schoolId] [int] NOT NULL,

[schoolName] [varchar](200) NULL, /*学校名称*/

[placeCount] [int] NULL,/*学校招收人数*/

[residue] [int] NULL/*学校剩余招收人数*/

)

go

/*学生填报志愿表*/

CREATE TABLE [bm_wish](

[wishId] [int] NOT NULL,

[personId] [int] NULL, /*学生id*/

[schoolId] [int] NULL,/*学生填报学校*/

[priority] [int] NULL/*学校志愿优先顺序*/

)

GO

数据初始化

/*-------------------------------学校和学生数据初始化-------------------------------------------------------*/

由于学校和学生的数据比较多,请自行随机生成

本人的学校测试数据为20个学校,学生测试数据为4000

---------------------------------随机初始化学校招生人数数据--------------------------------------------

DECLARE @COUNT INT = 0;

DECLARE @loopId INT = 1;

DECLARE @schoolId INT = 0;

SELECT @COUNT = COUNT(1)

FROM bm_school;

SELECT ID = IDENTITY(INT, 1,1),CONVERT(VARCHAR(50),schoolId) schoolId INTO #aa

FROM bm_school

while (@loopId <= @COUNT)

BEGIN

SELECT @schoolId = schoolId

FROM #aa

WHERE id = @loopId

UPDATE bm_school

SET placeCount = rand() * 250

WHERE schoolId = @schoolId

SET @loopId += 1;

END

DROP table #aa

-------------------------------------随机分配积分---------------------------------------------------------

DECLARE @COUNT INT = 0;

DECLARE @loopId INT = 1;

DECLARE @personId INT = 0;

DECLARE @random INT = 0;

DECLARE @id INT = 0;

SELECT @COUNT = COUNT(1)

FROM bm_person

while(@loopId <= @COUNT)

BEGIN

SELECT @personId = personId

FROM bm_person

WHERE personId = @loopId

SELECT

@id = id,

@random = random

FROM bm_random

WHERE isUsed = 0

ORDER BY NEWID()

UPDATE bm_random

SET isUsed = 1

WHERE id = @id

UPDATE bm_person

SET point = @random

WHERE personId = @personId

SET @loopId +=1;

END

-------------------------------------初始化学生志愿和志愿填报顺序--------------------------------------------------

DECLARE @personCount Int = 0 ;

DECLARE @personLoopId INt = 1;

DECLARE @personid INT = 0;

CREATE TABLE #priority(Id int IDENTITY(1,1), schoolId INT)

TRUNCATE TABLE bm_wish;

SELECT @personCount = count(1)

FROM bm_person

WHILE(@personLoopId <= @personCount)

BEGIN

Select @personid = personId

FROm bm_person

WHERE personid = @personLoopId

INSERT INTO bm_wish(personId,schoolId)

SELECT

@personid, schoolId

FROM bm_school;

INSERT INTO #priority

SELECT convert(VARCHAR(20),schoolId) schoolId

FROM bm_school

ORDER BY NEWID()

/*随机更新学生志愿的优先顺序*/

UPDATE bm_wish

SET priority = pr.id

FROM #priority pr, bm_wish bw

WHERE personId = @personId

And pr.schoolId = bw.schoolId

truncate TABLE #priority

SET @personLoopId += 1;

END

DROP TABLE #priority;

-----------------------------------------更新学生是否调剂志愿--------------------------------------------

DECLARE @personCount Int = 0 ;

DECLARE @personLoopId INt = 1;

SELECT @personCount = count(1)

FROM bm_person

print @personCount;

WHILE(@personLoopId <= @personCount)

BEGIN

print @personLoopId;

update bm_person

set isAdjust = CASE WHEN rand() > 0.5 THEN 1 ELSE 0 END

where personid = @personLoopId

SET @personLoopId += 1;

END

算法实现

/*

支持分数从高到低分配

支持按照学生志愿的优先顺序分配

支持学生的调剂分配

*/

ALTER PROCEDURE dbo.[Pro_StudentAssign]

@wishCount INT

AS

BEGIN;

BEGIN TRY;

BEGIN TRAN;

/*学生数*/

DECLARE @personCount INT = 0;

/*学生循环因子*/

DECLARE @personLoopId INT = 1;

/*学生志愿循环因子*/

DECLARE @wishLoopId INT = 1;

/*学校id*/

DECLARE @schoolId INT = 0;

/*学生id*/

DECLARE @personId INT = 0;

/*是否可以按志愿分配*/

DECLARE @isCanWish INT = 0;

/*是否调剂*/

DECLARE @isAdjust INT = 0;

/*可分配的学校学位总数*/

DECLARE @sumPlaceCount INT = 0;

SELECT

@sumPlaceCount = SUM(placeCount)

FROM bm_school

/*重置学校学位数*/

UPDATE bm_school

SET residue = placeCount

/*重置学生志愿分配结果*/

UPDATE bm_person

SET schoolId = 0,

isLose = 0;

/*按照积分从高到低读取学生数据*/

SELECT

CONVERT(VARCHAR,personId) personId,id=IDENTITY(INT,1,1), point,isAdjust

INTO #person

FROM bm_person

ORDER BY point DESC

/*读取学生数*/

SELECT

@personCount = COUNT(1)

FROM #person

/*遍历学生*/

WHILE(@personLoopId <= @personCount)

BEGIN

SET @wishLoopId = 1;

SET @schoolId = 0

SET @isCanWish = 0

SELECT

@personId = personId,

@isAdjust = isAdjust

FROM #person

WHERE Id = @personLoopId;

/*判断该学生是否可以按志愿分配学校学位*/

/*

是否按照志愿来分配受两个因素影响

1、填报的志愿个数

2、填报志愿的招收人数

*/

With TopCountWishCTE AS(

/*读取该学生的最优先的@wishCount个志愿*/

SELECT

TOP(@wishCount) *

FROM bm_wish

WHERE personId = @personId

ORDER BY priority ASC

)

SELECT @isCanWish = COUNT(1)

FROM bm_school bs

WHERE residue > 0

AND EXISTS(

SELECT

1

From TopCountWishCTE bw

Where bs.schoolId = bw.schoolId

);

print ('@isAdjust='+ convert(varchar, @isAdjust)+'@wishCount='+ CONVERT(varchar,@wishCount) +',@personId='+ convert(varchar, @personId) +',@isCanWish='+ convert(varchar,@isCanWish));

/*志愿内的学校学位未满,可以分配到学位*/

IF @isCanWish > 0

BEGIN

/*逐个检索填写优先志愿学校,若第一志愿已满,则检索第二个志愿,逐个检索*/

SELECT

Top 1 @schoolId = bw.schoolId

FROM bm_wish bw, bm_school bs

WHERE personId = @personId

AND bw.schoolId = bs.schoolId

AND bs.residue > 0

ORDER BY priority ASC

print '@schoolId = '+ convert(varchar,@schoolId);

END

ELSE

BEGIN

/*填报志愿学校学位已满并且接受调剂*/

IF @isAdjust = 1

BEGIN

/*随机读取一个有剩余学位的学校*/

SELECT

@schoolId = schoolId

FROM bm_school

WHERE residue > 0

ORDER BY NEWID()

END

ELSE

BEGIN

/*记录落选的学生*/

UPDATE bm_person

SET isLose = 1

WHERE personId = @personId

--PRINT '若未接受调剂有可能高分落榜,只能去读民办小学'

/*若未接受调剂有可能高分落榜,只能去读民办小学*/

END

END

/*若学生成功分配上则对学生标记学校学位,以及更新学位数*/

IF @schoolId > 0 And @schoolId IS NOT NULL

BEGIN

/*更新剩余的学位数*/

UPDATE bm_school

SET residue = residue - 1

WHERE schoolId = @schoolId

/*标记学生已经被分配上*/

UPDATE bm_person

SET schoolId = @schoolId

WHERE personId = @personId

END

SET @personLoopId += 1;

END

/*前@sumPlaceCount落选的高分学生占比*/

IF @personCount > 0

BEGIN

SELECT

COUNT(1) failCount,convert(DECIMAL(4,2),

COUNT(1) * 100.00 / (@sumPlaceCount * 1.00))failRate

From(

SELECT

TOP(@sumPlaceCount) *

FROM bm_person

ORDER BY Point DESC

)as TableLose

WHERE isLose = 1;

END

PRINT '@sumPlaceCount='+CONVERT(VARCHAR,@sumPlaceCount);

DROP TABLE #person;

COMMIT TRAN ;

END TRY

BEGIN CATCH

ROLLBACK TRAN ;

END CATCH

END;

结果测试

exec dbo.[Pro_StudentAssign] N;/*N为设定学生本次可填报的志愿个数,返回结果为高分落选占本次所有学校招生总数的比率*/

总结

由于本算法的中的测试样本是按照随机方式生成的,因此与实际填报情况是有差别的,但是根据人们的行为心理学分析,家长们都喜欢往好的报,比较理性的都会选择调剂保证能够上公办学校,因此实际情况中,学生高分的只要志愿填报合理并且接受调剂,就不会落选。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值