有关考试安排的算法(二)


分类: 算法 |
版权声明:本文为博主原创文章,未经博主允许不得转载。
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/1.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/2.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/3.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/14.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/15.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/16.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/17.jpg
http://p.blog.csdn.net/images/p_blog_csdn_net/smallfools/EntryImages/20091210/18.jpg
-
--重建考试安排表
-
truncate
table Exam -
--考场中可同时容纳的考生人数
-
declare
@MaxNumber int -
set
@MaxNumber = 900 -
--单场考试还能安排多少人数
-
declare
@RemainNum int -
--最始化:可安排人数与考场可容纳人数相同
-
set
@RemainNum = @MaxNumber -
--将学生选课表放在临时学生选课表中,这样就可以在临时选课表中随意地删除选课了
-
SELECT
StudentId, StudentName, CourseName -
into
#SelectCourse -
FROM
SelectCourse -
--先统计每门课程的考试人数,并放入临时统计表中
-
select
CourseName,count(CourseName) as ExamNum, as0 Arranged --Arranged:是否已安排;未安排为0,已安排为1 -
into
#CourseSelection -
from #SelectCourse -
group by CourseName -
order by ExamNum desc -
--创建一个临时冲突记录表,用于说明课程与课程之间是否冲突。这个冲突表相当于顶点图
-
CREATE
TABLE #CourseClash -
(
-
CourseA varchar(50) NOT NULL, --课程A -
CourseB varchar(50) NOT NULL, --课程B -
IfClash bit NOT NULL, --如果冲突则为1,如果不冲突则为0 -
ElectNum int NOT NULL --同时选择这两门课程的人数 -
)
-
--将课程与课程之间的冲突情况记录到临时冲突记录表中
-
while
(select count(CourseName) from #CourseSelection where Arranged=0)>0 -
begin -
--考试课程A -
declare @CourseNameA varchar(50) -
--考试课程B -
declare @CourseNameB varchar(50) -
--从临时统计表中取出一条记录 -
select top 1 @CourseNameA = CourseName from #CourseSelection where Arranged = 0 -
--将该课程标记为已安排 -
update #CourseSelection set Arranged=1 where CourseName = @CourseNameA -
--获取剩下的记录并放在游标里 -
declare aa cursor for -
select CourseName from #CourseSelection where Arranged = 0 -
--打开游标 -
open aa -
--从游标中获取一条记录 -
fetch next from aa into @CourseNameB -
--判断游标里是否还有记录 -
while(@@fetch_status=0) -
begin -
--判断课程A和课程B是否有冲突,即获得选择它们的学生的交集 -
declare @ElectNum int -
SELECT @ElectNum = COUNT(*) FROM -
(SELECT StudentId FROM #SelectCourse WHERE CourseName=@CourseNameA) AS SelectCourseA -
INNER JOIN -
(SELECT StudentId FROM #SelectCourse WHERE CourseName=@CourseNameB) AS SelectCourseB -
ON -
SelectCourseA.StudentId = SelectCourseB.StudentId -
--如果交集为0,则说明课程A和B没有冲突 -
if @ElectNum=0 -
begin -
--插入记录到临时冲突记录表 -
INSERT #CourseClash (CourseA,CourseB,IfClash,ElectNum) -
VALUES (@CourseNameA,@CourseNameB,0,0) -
INSERT #CourseClash (CourseA,CourseB,IfClash,ElectNum) -
VALUES (@CourseNameB,@CourseNameA,0,0) -
end -
else -
begin -
--插入记录到临时冲突记录表 -
INSERT #CourseClash (CourseA,CourseB,IfClash,ElectNum) -
VALUES (@CourseNameA,@CourseNameB,1,@ElectNum) -
INSERT #CourseClash (CourseA,CourseB,IfClash,ElectNum) -
VALUES (@CourseNameB,@CourseNameA,1,@ElectNum) -
end -
-
--从游标中获取下一条记录 -
fetch next from aa into @CourseNameB -
end -
--关闭游标 -
close aa -
deallocate aa -
end -
--考试场次
-
declare
@ExamScreenings int -
set
@ExamScreenings = 0 -
--安排的考试课程
-
declare
@ExamCourse varchar(50) -
--考试人数
-
declare
@ExamNum int -
set
@ExamNum = 0 -
while
(select count(*) from #SelectCourse)>0 -
begin
-
--首先获得选课最多的学生的选课,并将这些选课添加到考试安排表中 -
declare bb cursor for -
select #SelectCourse.CourseName,#CourseSelection.ExamNum from #SelectCourse -
inner join #CourseSelection on #CourseSelection.CourseName = #SelectCourse.CourseName -
where StudentId = (select top 1 StudentId from #SelectCourse group by StudentId order by count(StudentId) desc) -
--打开游标 -
open bb -
fetch next from bb into @ExamCourse,@ExamNum -
while(@@fetch_status=0) -
begin -
-
--考试场次 -
set @ExamScreenings = @ExamScreenings + 1 -
--最始化:可安排人数与考场可容纳人数相同 -
set @RemainNum = @MaxNumber -
-
--插入考试安排表 -
INSERT Exam (ExamScreenings,Course,ExamNum) VALUES (@ExamScreenings,@ExamCourse,@ExamNum) -
set @RemainNum = @RemainNum - @ExamNum -
------------------------------------------------------------------------------------------- -
--选出所有与该门考试不冲突的课程并且不是正要添加的选课,放在游标中,即有可能安排的课程 -
declare cc cursor for -
select #CourseClash.CourseB,#CourseSelection.ExamNum from #CourseClash -
inner join #CourseSelection on #CourseSelection.CourseName = #CourseClash.CourseB -
where #CourseClash.CourseA=@ExamCourse and #CourseClash.IfClash=0 -
and #CourseClash.CourseB not in -
(select #SelectCourse.CourseName from #SelectCourse -
where StudentId = -
(select top 1 StudentId from #SelectCourse group by StudentId order by count(StudentId) desc)) -
and #CourseSelection.ExamNum <=@RemainNum -
order by #CourseSelection.ExamNum desc --这里排序是按选课人数多少排,也可以按冲突人数多少来排 -
--将要安排的课程 -
declare @WillArrange varchar(50) -
-
--打开游标 -
open cc -
--取出一条记录 -
fetch next from cc into @WillArrange,@ExamNum -
while (@@fetch_status=0) -
begin -
--====================================================================================== -
--判断当前课程的选课人数是否大于考场可安排人数 -
if @ExamNum>@RemainNum -
begin -
fetch next from cc into @WillArrange,@ExamNum -
continue -
end -
--====================================================================================== -
--====================================================================================== -
--判断将要安排的课程和已安排的课程是否有冲突 -
--====================================================================================== -
--定义一个标识变量 -
declare @bFlag int -
set @bFlag = 0 -
--查找所有已安排的课程 -
declare dd cursor for -
select Course from Exam where ExamScreenings = @ExamScreenings -
--已安排的课程 -
declare @Arranged varchar(50) -
open dd -
fetch next from dd into @Arranged -
while (@@fetch_status=0) -
begin -
--判断将要安排的课程和已安排的课程是否有冲突 -
if (select top 1 IfClash from #CourseClash where CourseA=@WillArrange and CourseB=@Arranged)=1 -
begin -
--如果有冲突,则将标识变量设为1,跳出循环 -
set @bFlag = 1 -
break -
end -
fetch next from dd into @Arranged -
end -
--判断将要安排的课程是否和已安排的课程冲突 -
if (@bFlag=0) -
begin -
--如果不冲突,则在考场安排表中插入记录 -
INSERT Exam (ExamScreenings,Course,ExamNum) VALUES (@ExamScreenings,@WillArrange,@ExamNum) -
set @RemainNum = @RemainNum - @ExamNum -
end -
close dd -
deallocate dd -
--====================================================================================== -
fetch next from cc into @WillArrange,@ExamNum -
end -
--关闭游标 -
close cc -
deallocate cc -
------------------------------------------------------------------------------------------- -
--从临时学生选课表中删除该门选课 -
delete #SelectCourse where CourseName in (select Course from Exam where ExamScreenings=@ExamScreenings) -
--从临时统计表中删除该门课程 -
delete #CourseSelection where CourseName in (select Course from Exam where ExamScreenings=@ExamScreenings) -
--从冲突表中删除该门课程 -
delete #CourseClash where CourseA in (select Course from Exam where ExamScreenings=@ExamScreenings) -
or CourseB in (select Course from Exam where ExamScreenings=@ExamScreenings) -
fetch next from bb into @ExamCourse,@ExamNum -
end -
--关闭游标 -
close bb -
deallocate bb -
end
-
--删除临时表
-
drop
table #SelectCourse --临时选课表 -
drop
table #CourseSelection --临时统计表 -
drop
table #CourseClash --临时冲突表
原创不容易,转载请注明出处。http://blog.csdn.net/smallfools/archive/2009/12/10/4977414.aspx
相关文章: