Tenho me perguntado se existem soluções conhecidas para algoritmos de criação de um horário escolar. Basicamente, trata-se de otimizar a "dispersão de horas" (tanto no caso de professores como de classes) para determinadas associações classe-disciplina-professor. Podemos supor que temos conjuntos de classes, disciplinas de aula e professores associados entre si na entrada e que o horário deve caber entre 8h e 16h.
Acho que provavelmente não existe um algoritmo preciso para isso, mas talvez alguém conheça uma boa aproximação ou dicas para desenvolvê-lo.
Respostas:
Este problema é NP-Completo !
Em suma, é preciso explorar todas as combinações possíveis para encontrar a lista de soluções aceitáveis. Por causa das variações nas circunstâncias em que o problema aparece em várias escolas (por exemplo: Existem restrições em relação às salas de aula ?, Algumas das classes são divididas em subgrupos algumas vezes ?, Este é um horário semanal? etc.) não existe uma classe de problema bem conhecida que corresponda a todos os problemas de escalonamento. Talvez o problema da mochila tenha muitos elementos de semelhança com esses problemas em geral.
Uma confirmação de que este é um problema difícil e para o qual as pessoas sempre buscam uma solução, é verificar esta lista (longa) de ferramentas de programação de software (principalmente comerciais)
Por causa do grande número de variáveis envolvidas, a maior fonte das quais são, normalmente, os desejos do docente; -) ..., normalmente é impraticável considerar a enumeração de todas as combinações possíveis . Em vez disso, precisamos escolher uma abordagem que visite um subconjunto dos espaços de problema / solução.
- Algoritmos Genéticos , citados em outra resposta estão (ou, IMHO, parecem ) bem equipados para realizar este tipo de busca semi-guiada (O problema é encontrar uma boa função de avaliação para os candidatos a serem mantidos para a próxima geração)
- Gráfico Abordagens de reescrita também são úteis com este tipo de problemas de otimização combinatória.
Em vez de focar em implementações particulares de um programa gerador automático de agendamento, gostaria de sugerir algumas estratégias que podem ser aplicadas, no nível da definição do problema .
O raciocínio geral é que na maioria dos problemas de programação do mundo real, alguns compromissos serão necessários, nem todas as restrições, expressas e implícitas: serão satisfeitas totalmente. Portanto, ajudamos a nós mesmos:
Isso pode parecer contra-intuitivo, mas, por exemplo, ao fornecer um cronograma inicial parcialmente preenchido (digamos, cerca de 30% dos intervalos de tempo), de uma forma que satisfaça totalmente todas as restrições e, ao considerar este cronograma parcial imutável, reduzimos significativamente o tempo / espaço necessário para produzir soluções candidatas.
Outra forma de ajudar as restrições adicionais é, por exemplo, adicionar "artificialmente" uma restrição que impeça o ensino de algumas disciplinas em alguns dias da semana (se este for um horário semanal ...); esse tipo de restrição resulta na redução dos espaços de problema / solução, sem, normalmente, excluir um número significativo de bons candidatos.
Ao revisar esta resposta, percebo que é muito tímido em fornecer uma resposta definitiva, mas ainda assim cheia de sugestões práticas. Espero que ajude, com o que é, afinal, um "problema difícil".
fonte
É uma bagunça. uma bagunça real. Para complementar as respostas, já bastante completas, quero destacar minha experiência familiar. Minha mãe era professora e costumava participar do processo.
Acontece que ter um computador para fazer isso não é apenas difícil de codificar por si só, mas também porque existem condições que são difíceis de especificar para um programa de computador pré-preparado. Exemplos:
Como você pode ver, o problema não é NP-completo, é NP-insano.
Então, o que eles fazem é ter uma grande mesa com pequenas inserções de plástico e mover as inserções até que um resultado satisfatório seja obtido. Eles nunca começam do zero: normalmente partem do cronograma do ano anterior e fazem ajustes.
fonte
A Competição Internacional de Horários 2007 teve uma trilha de programação de aulas e uma trilha de programação de exames. Muitos pesquisadores participaram dessa competição. Muitas heurísticas e metaheurísticas foram tentadas, mas no final as metaheurísticas de busca local (como Tabu Search e Simulated Annealing) claramente venceram outros algoritmos (como algoritmos genéticos).
Dê uma olhada nas duas estruturas de código aberto usadas por alguns dos finalistas:
fonte
Uma das minhas atribuições de meio período era uma geração de tabelas escolares de algoritmo genético.
A mesa inteira é um "organismo". Houve algumas mudanças e advertências na abordagem dos algoritmos genéticos genéricos:
Regras foram feitas para "tabelas ilegais": duas turmas na mesma sala de aula, um professor ensinando duas turmas ao mesmo tempo etc. Essas mutações foram consideradas letais imediatamente e um novo "organismo" brotou no lugar do "falecido" imediatamente. O inicial foi gerado por uma série de tentativas aleatórias para obter uma tentativa legal (embora sem sentido). A mutação letal não foi contabilizada na contagem de mutações na iteração.
Mutações "Exchange" eram muito mais comuns do que mutações "Modify". As mudanças ocorreram apenas entre partes do gene que faziam sentido - sem substituir um professor por uma sala de aula.
Pequenos bônus foram atribuídos para agrupar certas 2 horas juntas, para atribuir a mesma sala de aula genérica em sequência para o mesmo grupo, para manter as horas de trabalho do professor e carga de aula contínua. Bônus moderados foram atribuídos para dar salas de aula corretas para determinado assunto, mantendo as horas de aula dentro de obrigações (manhã ou tarde), e assim por diante. Os grandes bônus eram para atribuir o número correto de determinada matéria, dada a carga de trabalho de um professor, etc.
Os professores poderiam criar seus cronogramas de carga de trabalho de "quero trabalhar então", "tudo bem para trabalhar então", "não gosta de trabalhar então", "não posso trabalhar então", com os pesos apropriados atribuídos. 24 horas inteiras eram horas de trabalho legais, exceto que a noite era muito indesejável.
A função de peso ... oh sim. A função de peso era um produto enorme e monstruoso (como na multiplicação) de pesos atribuídos a características e propriedades selecionadas. Era extremamente íngreme, uma propriedade facilmente capaz de mudá-la em uma ordem de magnitude para cima ou para baixo - e havia centenas ou milhares de propriedades em um organismo. Isso resultou em números absolutamente ENORMES como os pesos e, como resultado direto, é necessário usar uma biblioteca bignum (gmp) para realizar os cálculos. Para um pequeno teste de cerca de 10 grupos, 10 professores e 10 salas de aula, o conjunto inicial começou com uma nota de 10 ^ -200 algo e terminou com 10 ^ + 300 algo. Era totalmente ineficiente quando era mais plano. Além disso, os valores se distanciaram muito mais com "escolas" maiores.
Em termos de tempo de computação, havia pouca diferença entre uma população pequena (100) em um longo tempo e uma população grande (10k +) em menos gerações. O cálculo ao longo do mesmo tempo produziu aproximadamente a mesma qualidade.
O cálculo (em algumas CPUs de 1 GHz) levaria cerca de 1h para se estabilizar perto de 10 ^ + 300, gerando cronogramas que pareciam muito bons, para o referido caso de teste 10x10x10.
O problema é facilmente paralelizável ao fornecer facilidade de rede que trocaria os melhores espécimes entre computadores que executam a computação.
O programa resultante nunca viu a luz do dia lá fora me dando uma boa nota para o semestre. Ele se mostrou promissor, mas nunca tive motivação suficiente para adicionar qualquer GUI e torná-la utilizável para o público em geral.
fonte
Esse problema é mais difícil do que parece.
Como outros já mencionaram, este é um problema NP-completo, mas vamos analisar o que isso significa.
Basicamente, significa que você deve examinar todas as combinações possíveis.
Mas "olhar para" não diz muito o que você precisa fazer.
É fácil gerar todas as combinações possíveis. Pode produzir uma grande quantidade de dados, mas você não deve ter muitos problemas para entender os conceitos dessa parte do problema.
O segundo problema é julgar se uma dada combinação possível é boa, má ou melhor do que a solução "boa" anterior.
Para isso, você precisa mais do que apenas "é uma solução possível".
Por exemplo, o mesmo professor trabalha 5 dias por semana durante X semanas seguidas? Mesmo que seja uma solução viável, pode não ser melhor do que alternar entre duas pessoas para que cada professor faça uma semana cada. Oh, você não pensou sobre isso? Lembre-se de que você está lidando com pessoas, não apenas com um problema de alocação de recursos.
Mesmo se um professor pudesse trabalhar em tempo integral por 16 semanas consecutivas, isso poderia ser uma solução abaixo do ideal em comparação com uma solução em que você tenta alternar entre os professores, e esse tipo de equilíbrio é muito difícil de incluir no software.
Para resumir, produzir uma boa solução para esse problema valerá muito, para muitas pessoas. Portanto, não é um problema fácil de analisar e resolver. Esteja preparado para definir alguns objetivos que não sejam 100% e chamá-los de "bons o suficiente".
fonte
Meu algoritmo de cronograma, implementado em FET (Free Timetabling Software, http://lalescu.ro/liviu/fet/ , um aplicativo de sucesso):
O algoritmo é heurístico. Eu o chamei de "troca recursiva".
Entrada: um conjunto de atividades A_1 ... A_n e as restrições.
Saída: um conjunto de tempos TA_1 ... TA_n (o intervalo de tempo de cada atividade. Os quartos são excluídos aqui, para simplificar). O algoritmo deve colocar cada atividade em um intervalo de tempo, respeitando as restrições. Cada TA_i está entre 0 (T_1) e max_time_slots-1 (T_m).
Restrições:
C1) Básico: lista de pares de atividades que não podem ser simultâneas (por exemplo, A_1 e A_2, porque têm o mesmo professor ou os mesmos alunos);
C2) Muitas outras restrições (excluídas aqui, para simplificar).
O algoritmo de tabela de horários (que denominei "troca recursiva"):
Tente colocar cada atividade (A_i) em um intervalo de tempo permitido, seguindo a ordem acima, uma de cada vez. Procure um slot disponível (T_j) para A_i, no qual esta atividade pode ser colocada respeitando as restrições. Se houver mais slots disponíveis, escolha um aleatório. Se nenhum estiver disponível, faça a troca recursiva:
a . Para cada intervalo de tempo T_j, considere o que acontece se você colocar A_i em T_j. Haverá uma lista de outras atividades que não concordam com esta mudança (por exemplo, a atividade A_k está no mesmo slot T_j e tem o mesmo professor ou os mesmos alunos que A_i). Mantenha uma lista de atividades conflitantes para cada intervalo de tempo T_j.
b . Escolha um slot (T_j) com o menor número de atividades conflitantes. Digamos que a lista de atividades neste slot contenha 3 atividades: A_p, A_q, A_r.
c . Coloque A_i em T_j e torne A_p, A_q, A_r não alocado.
d . Tente recursivamente colocar A_p, A_q, A_r (se o nível de recursão não for muito grande, digamos 14, e se o número total de chamadas recursivas contadas desde a etapa 2) em A_i começou não é muito grande, digamos 2 * n), como na etapa 2).
e . Se colocado A_p, A_q, A_r com sucesso, retorna com sucesso, caso contrário, tente outros intervalos de tempo (vá para a etapa 2 b) e escolha o próximo melhor intervalo de tempo).
f . Se todos (ou um número razoável de) slots de tempo foram tentados sem sucesso, retorne sem sucesso.
g . Se estivermos no nível 0 e não tivermos sucesso em colocar A_i, coloque-o como nos passos 2 b) e 2 c), mas sem recursão. Temos agora 3 - 1 = 2 mais atividades para realizar. Vá para a etapa 2) (alguns métodos para evitar ciclos são usados aqui).
fonte
ATUALIZAÇÃO: dos comentários ... deve ter heurísticas também!
Eu escolheria Prolog ... então usaria Ruby ou Perl ou algo assim para limpar sua solução para uma forma mais bonita.
Estou (ainda) no processo de fazer algo semelhante a este problema, mas usando o mesmo caminho que acabei de mencionar. Prolog (como uma linguagem funcional) realmente torna mais fácil resolver problemas NP-Hard.
fonte
Algoritmos genéticos são freqüentemente usados para tal programação.
Encontrei este exemplo (Fazendo Cronograma de Aula Usando Algoritmo Genético) que corresponde muito bem aos seus requisitos.
fonte
Aqui estão alguns links que encontrei:
Horário escolar - lista alguns problemas envolvidos
Um Algoritmo Genético Híbrido para Horários Escolares
Utilitários e ferramentas de agendamento
fonte
Este artigo descreve muito bem o problema do horário escolar e sua abordagem ao algoritmo: " The Development of SYLLABUS — An Interactive, Constraint-Based Scheduler for Schools and Colleges. " [PDF]
O autor me informa que o software SYLLABUS ainda está sendo usado / desenvolvido aqui: http://www.scientia.com/uk/
fonte
Trabalho em um mecanismo de agendamento amplamente usado que faz exatamente isso. Sim, é NP-completo; as melhores abordagens procuram aproximar uma solução ótima. E, claro, existem muitas maneiras diferentes de dizer qual é a "melhor" solução - é mais importante que seus professores estejam satisfeitos com seus horários, ou que os alunos participem de todas as aulas, por exemplo?
A questão absolutamente mais importante que você precisa resolver no início é o que torna uma maneira de programar este sistema melhor do que outra ? Isto é, se eu tenho um horário com a Sra. Jones ensinando Matemática aos 8 e o Sr. Smith ensinando Matemática aos 9, isso é melhor ou pior do que um com os dois ensinando Matemática aos 10? É melhor ou pior do que um com a Sra. Jones ensinando aos 8 e o Sr. Jones ensinando aos 2? Por quê?
O principal conselho que eu daria aqui é dividir o problema tanto quanto possível - talvez curso por curso, talvez professor por professor, talvez sala por sala - e trabalhar primeiro para resolver o subproblema. Lá você deve acabar com várias soluções para escolher e precisa escolher uma como a mais provável ideal. Em seguida, trabalhe para fazer com que os subproblemas "anteriores" levem em consideração as necessidades dos subproblemas posteriores ao pontuar suas soluções potenciais. Em seguida, talvez trabalhe em como se livrar de situações imprecisas (supondo que você não possa antecipar essas situações em subproblemas anteriores) quando chegar a um estado de "soluções sem validade".
Um passo de otimização de busca local é freqüentemente usado para "polir" a resposta final e obter melhores resultados.
Observe que normalmente estamos lidando com sistemas altamente restritos de recursos na programação escolar. As escolas não passam o ano com muitas salas vazias ou professores sentados na sala 75% do dia. As abordagens que funcionam melhor em ambientes ricos em soluções não são necessariamente aplicáveis na programação escolar.
fonte
Eu projetei algoritmos comerciais para os horários das aulas e dos exames. Para o primeiro, usei programação inteira; para o segundo, uma heurística baseada na maximização de uma função objetivo escolhendo trocas de slots, muito semelhante ao processo manual original que havia sido desenvolvido. As principais coisas para que essas soluções sejam aceitas são a capacidade de representar todas as restrições do mundo real; e para que os cronômetros humanos não consigam ver maneiras de melhorar a solução. No final, a parte algorítmica foi bastante direta e fácil de implementar em comparação com a preparação dos bancos de dados, a interface do usuário, a capacidade de relatar estatísticas como utilização da sala, educação do usuário e assim por diante.
fonte
Geralmente, a programação de restrição é uma boa abordagem para esse tipo de problema de agendamento. Uma pesquisa sobre "programação de restrição" e agendamento ou "agendamento baseado em restrição" tanto no estouro de pilha quanto no Google irá gerar algumas boas referências. Não é impossível - é um pouco difícil pensar sobre o uso de métodos de otimização tradicionais, como otimização linear ou inteira. Uma saída seria - existe uma programação que satisfaça todos os requisitos? Isso, por si só, é obviamente útil.
Boa sorte !
fonte
Você pode lidar com isso com algoritmos genéticos, sim. Mas você não deve :). Pode ser muito lento e o ajuste dos parâmetros pode ser muito demorado, etc.
Existem outras abordagens bem-sucedidas. Tudo implementado em projetos de código aberto:
Veja aqui uma lista de software de tabela de horários
fonte
Acho que você deve usar algoritmo genético porque:
A qualidade da solução depende de quanto tempo você pretende gastar resolvendo o programa.
Definição de Algoritmos Genéticos
Tutorial de Algoritmos Genéticos
Projeto de agendamento de aulas com GA
Também dê uma olhada em: uma pergunta semelhante e outra
fonte
Não sei se alguém vai concordar com este código, mas desenvolvi este código com a ajuda do meu próprio algoritmo e está trabalhando para mim em ruby. Espero que ajude os que estão procurando por ele no código a seguir the periodflag, dayflag subjectflag e teacherflag são o hash com o id correspondente e o valor do flag, que é booleano. Qualquer problema entre em contato comigo ....... (-_-)
periodflag.each do | k2, v2 |
fonte