回答

收藏

SQL高效的计划生成算法

技术问答 技术问答 312 人阅读 | 0 人回复 | 2023-09-14

这个主意想象一下设备 分支机构的    教育中心。教育中心 课程    对所有分支机构都是通用的。
  U5 s8 V$ n6 w) a, {  g分行+ I0 I6 o; {. |  t& S$ K5 ^
CREATE TABLE `Branch` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;CREATE TABLE `Course` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `active` tinyint(1) DEFAULT '1', PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;*管理员生成的每门课程的每个分支 *房间    。例如,管理员输入数学课程的房间数。系统生成三个房间。换句话说,它们受到计数的限制。4 ]0 g' v/ {5 ]% g) m- Q
CREATE TABLE `Room` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(255) DEFAULT NULL, `branch_id` int(10) unsigned DEFAULT NULL, `course_id` int(10) unsigned DEFAULT NULL, `occupied_hours` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;每个房间每天有5个教学时间。换句话说,Math-每小时(共5个)将有一个不同的学生组。
4 K# C: _! o$ v* ]- `0 V5 T学生    -也按分支分组。每个学生都喜欢按周计划(week_day_mode)上中学。
1 G5 _2 L$ o7 z9 ]" j  p. x一周1、3、5天+ M8 Q5 g& G5 z% l( i% w/ Y7 u- A5 f
一周2、4、6天
class 这个字段是学校(主要学校)的年级,
3 @0 @5 b/ X/ Y+ ?* M6 aCREATE TABLE `Student` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `fullname` varchar(255) NOT NULL, `class` tinyint(2) DEFAULT NULL, `branchID` int(10) unsigned DEFAULT NULL, `week_day_mode` tinyint(1) DEFAULT NULL, PRIMARY KEY (`id`), KEY `branchID` (`branchID`)) ENGINE=InnoDB AUTO_INCREMENT=246 DEFAULT CHARSET=utf8;当管理员第一次注册学生时,他会选择学生想要参加的所有课程。例如,如果选择5门课程StudentCourseAssoc将为学生填写5行。管理员在测试了每门课程的基本知识水平后,将学生评估为特定课程的聪明( 1)或愚蠢(-1)。所以knowledge_level学生课程连接的价值。, ?; }, `) z" Q! z
CREATE TABLE `StudentCourseAssoc` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `studentID` int(10) unsigned DEFAULT NULL, `courseID` int(10) unsigned DEFAULT NULL, `knowledge_level` tinyint(1) DEFAULT NULL, `group_id` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=1144 DEFAULT CHARSET=utf8;应用程序必须:+ l% e: f8 h9 v1 t5 T
每个分支的学生在以下条件下自动分组(可创建新分组或将学生添加到现有分组)  z* o' b$ ~! u0 A5 P2 ^* K$ j7 L1 x
聪明愚蠢的学生必须分为不同的小组. b# o# N( n/ F! Y! y: s4 I0 ~
小组可能由一些年级组成。所以9年级和10年级可以混合使用。和11级一起毕业(12级意味着sql毕业)。但不是10日到11日。(有两种模式:9-10、11-12)
% }% a' n8 x/ \小组最多可容纳8名学生。
4 d4 g1 w& j  K" a- S教室有限。因此,每个房间每天只能容纳5个小组。* r, G) R6 K5 V  u9 [) C
每个学生必须在一天内完成每门课程(由他自己选择)
搜索group在满足上述条件后,如果找不到,必须创建应用程序,然后将学生分配给学生group。然后 :  }3 R! s6 ?" b6 m/ A
CREATE TABLE `StudentGroupAssoc` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `group_id` int(10) unsigned DEFAULT NULL, `student_id` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id`)) ENGINE=InnoDB AUTO_INCREMENT=11 DEFAULT CHARSET=utf8;CREATE TABLE `Schedule` (  `id` int(10) unsigned NOT NULL AUTO_INCREMENT, `group_id` int(10) unsigned DEFAULT NULL, `week_day_mode` tinyint(1) DEFAULT NULL, `hour` tinyint(1) DEFAULT NULL,    `room_id` int(4) unsigned DEFAULT NULL, `teacher_id` int(10) unsigned DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `Unique Room for exact time` (`week_day_mode`,`hour`,`room_id`) USING BTREE, UNIQUE KEY `Unique Group for exact time` (`group_id`,`week_day_mode`) USING BTREE, KEY `Unique Teacher for exact time` (`week_day_mode`,`hour`,`teacher_id`), KEY `room_id` (`room_id`), KEY `teacher_id` (`teacher_id`)) ENGINE=InnoDB DEFAULT CHARSET=utf8;和这里玩弄小提琴。我做了什么我正在尝试group让学生在知识评估期间参与(现有或创建新的)。例如,如果学生选择数学作为课程之一,当管理员评估他的数学知识并给出积极的评估时,程序将开始为学生选择合适的小组:, _4 h1 m5 b/ n8 n- k1 ~
功能标记学生的知识水平
+ ~" }3 s, W/ C, q* O4 l3 I检查学生的可用时间(比如已经采用了第一个小时,那么他有4个小时)) L) w3 x( f+ }# B" m2 `: q$ G
将全班学习条件添加到搜索中(例如9)-10年级或11-12年级)7 g+ n# T6 ^0 I% x7 S% G$ l
检查时间表中学生每周计划中是否有可用时间
如果没有人,试着创造。
0 J% K7 Q1 A& G# o所以PHP看起来像这样
, _/ h$ n( L/ l4 V                                sets knowledge level of student        $studentCourse->knowledge_level = intval($_POST["mark"]);      check hours of student,and keep only available hours        $availableHours = array_combine(range(1,5),range(1,5));      Unsets students unavailable hours from possible hours        if ($student->GroupRels)            foreach ($student->GroupRels as $groupRel)                unset($availableHours[$groupRel->hour]);      Checks available groups based on class coverage        if (in_array($student->class,['11','G)$classCoverage = "11-m";        else if (in_array($student->class,['9','10)$classCoverage = "9-10";        $availableGroups = Group::find()          ->with("schedule")            ->where([                "Group.class_coverage" => $classCoverage,                   "Group.knowledge_level" => $studentCourse->knowledge_level,                   "Group.participiant_count $availableHours,             Schedule.week_day_mode' => $student->week_day_mode            ->all();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;if (count($availableGroups) >        Selecting one of groups      adding row to StudentGroupAssoc      adding row to Schedule      else                $group = new Group();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;$group->branch_id = $student->branchID;            $group->class_coverage = $classCoverage;            $group->course_id=$studentCourse->courseID;            $group->knowledge_level=$studentCourse->knowledge_level;            $group->save();;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;...      adding row to StudentGroupAssoc      adding row to Schedule      问题是从理论上讲,我的工作方式就像购买飞机票。是无错的,并且必须有效,但是效率不高且不是最佳的。必须以最有效的方式满足所有分组条件:最少的组数和满足有限的房间数策略。这种方法很快将组成大量的组,这些组将不适合可用的房间时间。
; h' P6 [) ?+ Y4 p  D当我在评估过程中一小时学习学生时,越来越难得到真正有效的结果。由于房间有限,越来越多的学生花了几个小时找不到学生组,创建新组。
* j8 Y- U5 a: Q您建议在每个房间中利用什么小时?
6 |6 r  T% n' Y: R% r更新基于@norbert_van_nobelen为了获得每个学生所有可能的时空课程组合列表,我创建了虚拟小时表和以下视图。
. c5 s  O7 B3 zhours计划的实际小时数 hours_available是二进制开关。因此,我们在实际代码中添加了一个where子句:WHERE7 J3 A1 r; g. s, j
hours_available = 0只需获得我们计划的小时数:6 k0 T" I9 T/ K; P5 u8 I
SELECT    `s`.`id` AS `student_id`,IF ((ifnull(`sch`.`hour`,0) > 0),1,0) AS `hour_available`,`d`.`hours` AS `hours`,`sca`.`courseID` AS `courseID`,`sch`.`room_id` AS `room_id`,`sca`.`knowledge_level` AS `knowledge_level`,(    CASE    WHEN (       (`s`.`class` =9)           OR (`s`.`class` = 10)    THEN   -10'    WHEN (       (`s`.`class` =        OR (`s`.`class` = 12)     THEN   -12'    ELSE      END) AS `class_variant`FROM    (       (            (               (                   `dummy_hours` `d`                    JOIN `Student` `s`             LEFT JOIN `StudentCourseAssoc` `sca` ON ((`s`.`id` = `sca`.`studentID`))          LEFT JOIN `StudentGroupAssoc` `b` ON ((`s`.`id` = `b`.`student_id`))       LEFT JOIN `Schedule` `sch` ON (           (               (                   `sch`.`group_id` = `b`.`group_id`             AND (`d`.`hours` = `sch`.`hour`)           )    )使用此视图可以充分了解当前情况。但我仍然不知道算法
8 r) i" u: Q, N  M学生分组
$ n2 P1 U  q2 o8 P4 k! {& H把团体放在房间里
以最有效、最优化的方式创建最少的组数。
# d/ U* f' }- H' _! X有什么建议?
0 d5 Z4 R* T( m& B9 m) \                                                                " _" v4 @- l# k) O# C% Q
    解决方案:                                                                1 M- I- W  M5 J; U( g  f, u1 i
                                                                这个答案只是解决方案的方向,而不是100%好的解决方案:8 F# z# y9 ^/ S, D
您创建的内容需要循环才能满足所有条件。3 [' H6 Q3 m( \5 h& ?. E
为了更快地解决这种情况,实际上可以用向量代替,向量中的所有位置都由0(可用)和1(可用)表示。
' k, D; A$ }4 ^4 x1 v. @因此,student / math-1问题:' Z9 c+ Z) |6 W0 \- b# N* ^! c
假设有两个房间和三个小时:每个房间math-1向量为:
$ E( B* J) ]) O4 R' TRoom 1: Room 2: 本质上(至少我不在乎)只要有一个房间就可以使用一个房间:所以,在这种情况下,每个索引AND答案可能是可用性(请记住:0可用性):4 O- D$ A" n# o7 y4 [
会议室1:[1 0 0]会议室2:[0 0]房间结果:[1 00]和[0 00] 0]= [0 0 0]
. \, e5 x( P1 {1 X! ^  Q3 J因此,AND可以判断第一个小时是否可用。
0 _6 u; @9 }8 f$ f( L$ }假如现在把它和有可用时间的学生结合起来(这个例子只有3):2 s7 P9 X) l& A/ q
学生A:[0 0 1]房间结果:[0 0 0]学生使用此操作OR匹配房间:[0 0 1]或[0 0] 0]= [0 0 1]' _# L3 C. H3 h* V$ V8 G! F
因此,学生A与房间结果相匹配。" B; w3 @3 q6 f' q
在SQL中:数据模型(部分:缺乏匹配):表房:
# c. |# o6 O4 }4 dCREATE TABLE room(room_id INT,space TINYINT DEFAULT 0,hour INT DEFAULT 1);CREATE TABLE student(student_id INT,space TINYINT DEFAULT 0,hour INT DEFAULT 1)所有数据都插入到表中:在这种情况下,有一个房间,3小时,3个位置可用。4 U2 m2 e# Y6 h( }5 H5 C& |. t! k
INSERT INTO room VALUES (1,0,1);INSERT INTO room VALUES (1,0,1);INSERT INTO room VALUES (1,0,1);INSERT INTO room VALUES (1,0,2);INSERT INTO room VALUES (1,0,2);INSERT INTO room VALUES (1,0,2);INSERT INTO room VALUES (1,0,3);INSERT INTO room VALUES (1,0,3);INSERT INTO room VALUES (1,0,3);学生有:4 k5 l# a, J7 T$ c) C9 D" y
INSERT INTO student VALUES(1,0,1);  INSERT INTO student VALUES(1,0,2);   INSERT INTO student VALUES(1,1,3);所以学生前两个小时才有空。
( g0 c, P3 B9 I! ^从查询中获得结果:
. q  L1 e  S" d: \1 `1 R9 [SELECT room_idFROM room aINNER JOIN student b ON a.space=b.space AND a.hour=b.hour;这个结果最多只需要分成8个组,在这个组中SQL部分的结尾是另一种编程语言的时间。
" z7 z/ n0 ]! u" Q: U该模型可以增加日期,但在只使用小时和工作日(工作日可用性再次为0或1)时,效果最好。* Q  `) d& r8 `5 ^0 P+ w
正如我所说,这是一个概念/想法,而不是100%解决方案,所以在使用之前需要做一些工作......
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则