Uma equipe decidiu que todas as manhãs alguém deveria trazer croissants para todos. Não deve ser a mesma pessoa todas as vezes; portanto, deve haver um sistema para determinar de quem é a próxima vez. O objetivo desta pergunta é determinar um algoritmo para decidir de quem será a vez de trazer croissants amanhã.
Restrições, premissas e objetivos:
- De quem é a vez de trazer croissants será determinado na tarde anterior.
- Em qualquer dia, algumas pessoas estão ausentes. O algoritmo deve escolher alguém que estará presente naquele dia. Suponha que todas as ausências sejam conhecidas com um dia de antecedência, para que o comprador do croissant possa ser determinado na tarde anterior.
- No geral, a maioria das pessoas está presente na maioria dos dias.
- No interesse da justiça, todos devem comprar croissants tantas vezes quanto os outros. (Basicamente, suponha que todo membro da equipe tenha a mesma quantia de dinheiro para gastar em croissants.)
- Seria bom ter algum elemento aleatório, ou pelo menos percebido aleatoriedade, a fim de aliviar o tédio de uma lista. Esta não é uma restrição difícil: é mais um julgamento estético. No entanto, a mesma pessoa não deve ser escolhida duas vezes seguidas.
- A pessoa que traz os croissants deve saber com antecedência. Portanto, se a pessoa P trouxer croissants no dia D, esse fato deve ser determinado em um dia anterior em que a pessoa P está presente. Por exemplo, se o portador de croissant é sempre determinado no dia anterior, deve ser uma das pessoas presentes no dia anterior.
- O número de membros da equipe é pequeno o suficiente para que os recursos de armazenamento e computação sejam efetivamente ilimitados. Por exemplo, o algoritmo pode contar com uma história completa de quem trouxe croissants quando no passado. Até alguns minutos de computação em um PC rápido todos os dias seria bom.
Este é um modelo de um problema do mundo real; portanto, você pode desafiar ou refinar as suposições se achar que elas modelam melhor o cenário.
Origem: Descubra quem vai comprar os croissants de Florian Margaine . Minha reformulação aqui tem requisitos ligeiramente diferentes.
algorithms
scheduling
Gilles 'SO- parar de ser mau'
fonte
fonte
Respostas:
Existem duas categorias de soluções para esse tipo de problema: loterias tendenciosas e seqüências aleatórias filtradas / geradas .
Primeiro, vamos dispensar soluções fáceis, mas erradas, que não mantêm nenhum estado. Qualquer solução no estilo de loteria que não mantenha nenhum estado terá o número de vitórias em uma distribuição binomial, que falha no critério "quantas vezes". Você pode selecionar uma sequência aleatória que escolha todas as pessoas da mesma forma (basta dar uma olhada na lista; as permutações fornecem aleatoriedade), mas quando as pessoas começam a sair de férias, sua sequência agora tem falhas. A menos que você acompanhe, você se encontrará novamente com distribuições binomiais em vez de manter o mesmo esforço.
Vamos também nos comprometer a ter aleatoriedade real. Você pode querer isso para que, por exemplo, uma pessoa não possa agendar suas férias com base em um algoritmo determinístico, para que nunca esteja presente quando for a sua vez de comprar croissants (até que eles usem todos os dias de férias, suponho). .
Então, vamos aos dois tipos de soluções.
Para construir uma loteria tendenciosa, observe primeiro que podemos escolher praticamente qualquer distribuição contínua (com desvio finito) para gerar números para nossa loteria. O perdedor pode então ser a pessoa com o menor número. O viés mais simples é acompanhar se cada indivíduo comprou mais ou menos do que sua parte. Você pode medir o viés em unidades de croissants. Você pode ajustar o grau de aleatoriedade alterando a largura e o formato da distribuição - isso também determinará a que distância um indivíduo pode chegar "do mesmo número de vezes". Gaussianos são fáceis; eles permitem uma surpresa razoável sem ter caudas muito longas ("injustas"). Portanto, o formato básico da solução é (no código Scala)
Você pode acompanhar quem comprou por último e dar a eles um grande bônus de viés (por exemplo
10*stdev
) para impedir que as pessoas comprem duas vezes seguidas, exceto no caso em que a estrutura de férias permitiu que todos comprassem a "última" vez. (ou seja, você compra e depois sai de férias.) A mesma coisa por não estar presente no dia em que foram selecionados. (Se alguém está ausente todos os outros dias eles eventualmente vão vir para cima como eles queimam através de seu bônus de viés;. Eu considero este um recurso e não um bug)Então, você coleciona sua lista de funcionários atuais para o dia, faz com que todos rolem para a loteria, escolham a mais baixa e atualizam. Você pode escolher se o bônus de compra é igual ao número de funcionários (bom quando o custo é insignificante, mas a viagem para obter croissants é onerosa), o número de funcionários presentes (bom se a viagem é fácil, mas o custo é oneroso) ) ou algo no meio (para reconhecer os dois encargos). Provavelmente, é melhor ter apenas a penalidade de "comer" para as pessoas presentes, mas você pode fazê-lo de qualquer maneira, se achar que apenas estar de férias não lhe dá o tom certo em menos.
Para construir uma sequência aleatória filtrada, primeiro você precisa gerar uma sequência aleatória. Baralhar uma lista dos funcionários é a melhor maneira de começar. Basta percorrer a lista, em ordem, dia após dia. Se alguém não puder comprar porque está ausente ou não pode ser avisado ou comprado antes, pule-o. Agora você tem um problema: você está acumulando pessoas que foram ignoradas. Tudo bem, no entanto. Quando você chegar ao final da sua sequência, anexe a lista de funcionários ignorados à lista completa antes de embaralhar. Agora, a probabilidade de ocorrência é proporcional ao número de vezes que você foi ignorado, o que mantém a propriedade "mesmo número de vezes".
Pessoalmente, sou a favor da solução tendenciosa da loteria, pois o controle sobre a aleatoriedade é melhor. Com sequências filtradas, você pode criar maneiras mais complexas de gerar sequências. Por exemplo, em vez de fazer uma permutação aleatória, faça trocas locais a uma certa distância ou permita a troca total de pessoas da piscina (mas elas vão para a lista ignorada) - mas essas coisas exigem mais esforço algorítmico. Com a loteria, você apenas ajusta o desvio padrão.
fonte
E quando isso dura para sempre, eles vivem felizes, dividindo igualmente o preço do croissant.
Ps: Desculpe pelo mau inglês, mas não sou falante nativo e já é tarde ... sinta-se à vontade para corrigir erros (e pode adicionar algumas especiarias à história ...)
fonte
Toda iteração que você tem
Se você escolher uma pessoa aleatoriamente entre as pessoas da lista e excluir o comprador anterior, você alcançará seus objetivos:
Outros algoritmos que eu vi propostos são menos aleatórios ou menos justos:
Os algoritmos de "baralhamento da plataforma" não são realmente aleatórios no sentido de que a probabilidade de pagamento não é constante (1 / N na primeira escolha, 1 / (N-1) na segunda ... 1 na Nª escolha - - se um ainda não foi escolhido). Além disso, se você for escolhido primeiro, terá exatamente zero chances de ser escolhido pelos próximos N tempos. O sistema é facilmente quebrado, chegando raramente até ser escolhido e depois constantemente.
Os algoritmos "compensatórios" que tentam fazer com que todos obtenham ativamente o mesmo número de croissants, em vez de confiar nas propriedades de números aleatórios, deixam de ser aleatórios ou justos (ou ambos).
fonte