Descubra de quem é a vez de comprar os croissants

9

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.

Gilles 'SO- parar de ser mau'
fonte
11
Qual era exatamente a pergunta? Podemos assumir que as pessoas estão ausentes mais ou menos a mesma quantidade? O que há de errado em considerar a pessoa que fez isso o menor número de vezes, ou simplesmente uma pessoa aleatória?
24913 Pål GD
@ PålGD Assumir que as pessoas estão ausentes aproximadamente na mesma quantidade seria uma simplificação. Faça isso se quiser, mas se o seu algoritmo funcionar para meio período, é melhor. Tomar a pessoa que fez isso o menor número de vezes é uma solução (embora tenha em mente o requisito de que ela conhece um dia antes, isso torna a solução não completamente trivial). Uma pessoa aleatória também pode funcionar, mas a aleatoriedade introduz um desvio da justiça que você pode querer vincular.
Gilles 'SO- stop be evil'
O que? Nenhuma imagem salivante? Você quer que sejamos escravos em nossa mesa fazendo matemática em vez de sairmos para a padaria?
Caleb
@Gilles - FYI, executando um experimento no P.SE com sua versão desta pergunta . Agora que os dois sites são um pouco mais antigos, estou curioso para ver como as respostas de cada comunidade se moldam.

Respostas:

7

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.

  1. 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)

    case class Employee(var bias: Double) {
      def eat         { bias -= 1 }
      def buy(n: Int) { bias += n }
      def roll        = bias + stdev * Random.nextGaussian
    }
    

    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.

  2. 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".

    registro2(N)NN!NNregistro2[(N!NN)1 1/N]-1 1registro(2)+registro22π/NN-1.4NN=10 1,14

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.

Rex Kerr
fonte
4

{P1 1,...,Pn}vEuk-1 1PEuk-1 10 0

euvk=Eu=1 1n(vEuk)eu

kEu1 1-(vEuk)euvk

P1 1

P1 1

v

vEukkvk

PEu

PEuk+1 1kPjPj

PEuvEuk

E quando isso dura para sempre, eles vivem felizes, dividindo igualmente o preço do croissant.

P1 1eueueu=keu

P1 1P2

P1 1vEuk

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 ...)

wece
fonte
2

Toda iteração que você tem

  • Uma lista de pessoas presentes e disponíveis para compra
  • O comprador anterior

Se você escolher uma pessoa aleatoriamente entre as pessoas da lista e excluir o comprador anterior, você alcançará seus objetivos:

  1. O algoritmo é "maximamente" aleatório, pois usamos a quantidade mínima de informações da iteração anterior e escolhemos aleatoriamente.
  2. Em média, as pessoas pagam croissants (N / (N-1)) toda vez que participam de uma extração, tornando o algoritmo o mais justo possível.
  3. Eu sugeriria eliminar a regra de não repetição para tornar isso maximamente aleatório.

Outros algoritmos que eu vi propostos são menos aleatórios ou menos justos:

  1. 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.

  2. 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).

Sklivvz
fonte
Nm . Como existem soluções que nunca se desviam mais do queN/m1 1
N
@RexKerr, por que você compraria mais croissants do que funcionários?
Sklivvz
Estou confuso. Onde eu sugeri um?
Rex Kerr