Составить расписание всегда былом делом непростым. Доверить эту задачу компьютеру решались не все, потому что задача NP-полная и алгоритмического решения «в лоб» за обозримое время не имеет (объяснение). Недавно ко мне в руки попал пакет математического решателя IBM CPLEX Solver и я попробовала сделать помощника для составления школьного расписания.    Модель решила сделать целочисленную, еще её называют MIP. Действующих лиц у нас четыре. Поэтому пусть будет четыре оси системы координат. Т.е. наше пространство будет четырехмерным. Зададим их в виде одномерных массивов данных: Название оси Пример данных Пример в dat файле классы учеников 5а или 9б classes = {"5a", "5b", "6a", "6b", "7a", "7b", "8a", "8b", "9a", "9b","10a", "10b", "11a", "11b"}; учителя Иванова Мария Ивановна, Петрова Татьяна Сергеевна и т.д. teachers = {"ivanova", "petrova_en", "sidorova_ge", "shumova", "trudovik_m", "trudovik_w", "stoprtteacher"};    кабинеты    это про физические комнаты: 101 кабинет, спорт. зал, кабинет труда № 105, кабинет физики № 205 и т.д. rooms = {"18", "sport1", "trudy_m", "trudy_w" , "21","22","23","24", "25", "26", "27", "31","32","33","34"}; уроки это вакантные места в расписании. Выглядит это как 3х-значное число, в котором первая цифра – это номер дня от 1 до 6, если учатся по шестидневке и до 5, если по пятидневке    вторя цифра – номер смены 1 или 2    третья цифра – номер урока в смене. Обычно от 1 до 6 или до 7    // day,  shift, lesson number lessons = { 111, 112, 113, 114, 115, 116, 117, 121, 122, 123, 124, 125, 126, 127//, 211, 212, 213, 214, 215, 216, 217, 221, 222, 223, 224, 225, 226, 227, 311, 312, 313, 314, 315, 316, 317, 321, 322, 323, 324, 325, 326, 327, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 425, 426, 427, 511, 512, 513, 514, 515, 516, 517, 521, 522, 523, 524, 525, 526, 527, 611, 612, 613, 614, 615, 616, 617, 621, 622, 623, 624, 625, 626, 627 }; Между осями координат у нас получаются плоскости. И тут можно наложить ограничения на эти плоскости. Они представляют собой двумерные матрицы. В этих матрицах хранятся определенные целочисленные значения. Далее подробнее про каждое соотношение:    Название плоскости Пример Как выглядит в dat файле  Отношения между кабинетами и учителями Хранится целое число >= 0. Если учитель НЕ может работать в этом кабинете – то 0. Например, нельзя проводить физкультуру в кабинете математики. Но можно провести математику в кабинете физики. Тут будем играть приоритетами. 1 – самый лучший кабинет для этого учителя. 2 – не такой хороший, 3 – приемлемый, но нежелательный. Далее мы еще используем это в целевой функции.    roomTeachersRelation = [ [2,1,1,1,0,0,0], [0,0,0,0,0,0,1], [0,0,0,0,1,0,0], [0,0,0,0,0,1,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [2,1,1,1,0,0,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [2,1,1,1,0,0,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [2,1,1,1,0,0,0], [2,1,1,1,0,0,0] ]; Отношение между учителями и классами учеников Тут пишем сколько уроков в неделю должен провести конкретный учитель у конкретного класса. Например, Иванова М.И. должна провести 4 русских языка и 2 литературы в неделю у 6 Б класса. Значит в пересечении пишем цифру 4 + 2  = 6 teacherClassRelation = [ [2,1,0,0,1,1,0,0,0,0,0,0,0,0], [0,0,1,1,0,1,0,0,0,0,0,0,0,0], [0,0,1,0,1,0,0,1,1,0,0,0,1,0], [0,0,0,0,0,0,1,0,0,0,0,2,0,0], [0,0,0,1,0,0,1,0,0,1,1,0,1,1], [0,0,0,1,0,0,1,0,0,1,1,0,1,1], [1,0,1,0,1,0,0,1,1,0,0,1,0,0] ]; Отношение между классами учеников и уроками  Значения этой матрицы 0 или 1. А точнее тут мы задаем в какой смене учится класс. Если 0 – то класс не может иметь уроки в это время.    classLessonRelation = [ [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1] ]; Отношение между учителями и номером урока Значение этой матрицы 0 или 1. Если стоит 0 – значит учитель не может вести уроки в это время. Это на тот случай, если какой-то учитель может работать только в определённые дни недели. Например, учителя с маленькими детьми не работают по субботам. teacherLessonRelation = [ [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,0,0,0] ]; Графически все вместе (4 оси координат и соотношения между ними) можно представить, как четырёхмерный куб. У нас есть 4 измерения и 4 заданные поверхности. Можно ограничить и больше поверхностей, например, соотношение классов и кабинетов, если каким-то классам нельзя ставить уроки в этих кабинетах. Или между номером урока и кабинетом, если какой-то кабинет недоступен, например, в среду. Но пока ограничимся малым. В такой постановке задачи переменной для хранения результата являться 4х мерный массив, в котором каждое значение может быть 0 или 1. 1 - означает, что условия соотношений выполняется и урок может быть у данного класса, учителя в данном кабинете и в данное время.  0 - означает, что четыре условия не выполняются. Имея все данные и переменные следует задать ограничения. Самое строгое ограничение, что если в наших двумерных массивах встречается ноль, то и в результирующей переменной должен быть ноль Используем ограничение по поверхности между учителями и классами учеников    Мы знаем количество уроков в неделю, которое должен провести учитель у класса. Поэтому получаем такое ограничение: для каждого учителя и каждого класса сумма уроков в кабинетах должна быть равна цифре из нашего ограничения.    Используем ограничение по поверхности между кабинетами и номерами уроков В одном кабинете может проходить только один урок, что естественно Используем ограничение по поверхности между учителями и номерами уроков. Потому что один учитель может присутствовать только на одном уроке И последнее ограничение по поверхности между классами учеников и номерами уроков. Это ограничение самое сложное, потому что для таких предметов как иностранный язык, физкультура, труды, информатика характерно разделение на подгруппы. В реальной школе классы часто делятся на подгруппы: физкультура у юношей и девушек, труды у мальчиков и девочек, подгруппы по языку и информатике. У этой проблемы тоже есть решение: введем набор данных для хранения подмножества «особенных» учителей. Например, учителя иностранного: Тогда в ограничениях к модели напишем, что класс в одно и тоже время может быть у двух разных учителей и в разных кабинетах. При написании мат. модели требуется еще задать целевую функцию. Т.е. обозначить к чему мы стремимся. Тут нужно обратиться к пользователю и узнать, что для них важно. Первое, это чтобы уроки для учеников проводились как можно раньше в сутках. Т.е. желательно, чтобы все начинали учиться с первого урока своей смены. Второе требование, это чтобы учителя начинали работать пораньше. Третье условие, чтобы учителя вели уроки в приемлемых кабинетах. Но если это невозможно, то выбираем из того, что есть. Выглядит целевая функция следующим образом: Для удобства обработки результатов в более наглядном виде в OPL Studio я ввела дополнительные переменные Эти переменные копируют состояние соответствующих поверхностей в переменной schedule. Поэтому можно видеть такие полезные наглядные результаты rooms = {"18", "sport1", "trudy_m", "trudy_w" , "21","22","23","24", "25", "26", "27", "31","32","33","34"}; teachers = {"ivanova", "petrova_en", "sidorova_ge", "shumova", "trudovik_m", "trudovik_w", "stoprtteacher"}; foreignLangTeachers = {"petrova_en", "sidorova_ge"}; trudyTeachers = {"trudovik_m", "trudovik_w"}; informaticsTeachers = {"trudovik_m", "trudovik_w"}; sportTeachers = {"trudovik_m", "trudovik_w"}; classes = {"5a", "5b", "6a", "6b", "7a", "7b", "8a", "8b", "9a", "9b","10a", "10b", "11a", "11b"}; // day,  shift, lesson number lessons = { 111, 112, 113, 114, 115, 116, 117, 121, 122, 123, 124, 125, 126, 127//, /* 211, 212, 213, 214, 215, 216, 217, 221, 222, 223, 224, 225, 226, 227, 311, 312, 313, 314, 315, 316, 317, 321, 322, 323, 324, 325, 326, 327, 411, 412, 413, 414, 415, 416, 417, 421, 422, 423, 424, 425, 426, 427, 511, 512, 513, 514, 515, 516, 517, 521, 522, 523, 524, 525, 526, 527, 611, 612, 613, 614, 615, 616, 617, 621, 622, 623, 624, 625, 626, 627*/ }; roomTeachersRelation = [ [2,1,1,1,0,0,0], [0,0,0,0,0,0,1], [0,0,0,0,1,0,0], [0,0,0,0,0,1,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [2,1,1,1,0,0,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [2,1,1,1,0,0,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [1,2,1,1,0,0,0], [2,1,1,1,0,0,0], [2,1,1,1,0,0,0] ]; teacherClassRelation = [ [2, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], [0, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 0], [0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 2, 0, 0], [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1], [0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 0, 1, 1], [1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 1, 0, 0] ]; classLessonRelation = [ [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [1,1,1,1,1,1,1,0,0,0,0,0,0,0], [0,0,0,0,0,0,0,1,1,1,1,1,1,1], [0,0,0,0,0,0,0,1,1,1,1,1,1,1] ]; teacherLessonRelation = [ [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,0,0,0] ]; Это была тонировочная попытка автоматизировать составление школьного расписания. Следующим шагом должно быть написание программной «оболочки» для введение реальных данных. Разработчик, алгоритм-эксперт