Olası devamsızlıkları hesaba katarak kruvasanları kimin almanın kim olduğunu öğrenin


13

Bir ekip, her sabah birisinin herkese kruvasan getirmesi gerektiğine karar verdi. Her seferinde aynı kişi olmamalı, bu yüzden kimin sırayla olacağını belirleyen bir sistem olmalı. Bu sorunun amacı, yarın kruvasan getirmenin kimin sırası olacağına karar vermek için bir algoritma belirlemektir.

Kısıtlamalar, varsayımlar ve hedefler:

  • Kimin kruvasan getirmesi bir önceki öğleden sonra belirlenecek.
  • Herhangi bir günde, bazı insanlar yoktur. Algoritma o gün mevcut olacak birini seçmelidir. Tüm devamsızlıkların bir gün önceden bilindiğini varsayalım, böylece kruvasan alıcısı bir önceki öğleden sonra belirlenebilir.
  • Genel olarak, çoğu insan çoğu günlerde mevcuttur.
  • Adil olmak adına, herkes kruvasanları diğerlerinden daha fazla satın almalıdır. (Temel olarak, her ekip üyesinin kruvasanlara harcamak için aynı miktarda paraya sahip olduğunu varsayın.)
  • Bir listenin can sıkıntısını hafifletmek için bazı rasgelelik unsurları veya en azından algılanan rasgelelik unsurları olması iyi olurdu. Bu zor bir kısıtlama değildir: daha çok estetik bir yargıdır. Ancak, aynı kişi arka arkaya iki kez seçilmemelidir.
  • Kruvasanları getiren kişi önceden bilmelidir. Bu yüzden P kişisi D gününde kruvasan getirecekse, bu gerçek P kişisinin bulunduğu önceki bir günde belirlenmelidir. Örneğin, kruvasan getirici her zaman bir gün önce belirlenirse, bir gün önce mevcut olanlardan biri olmalıdır.
  • Ekip üyelerinin sayısı, depolama ve bilgi işlem kaynaklarının etkin bir şekilde sınırsız olacağı kadar azdır. Örneğin, algoritma geçmişte kruvasanları kimin getirdiğine dair tam bir geçmişe dayanabilir. Her gün hızlı bir bilgisayarda birkaç dakikaya kadar hesaplama iyi olurdu.

Bu gerçek bir dünya probleminin bir modelidir, bu yüzden senaryonun daha iyi modellendiğini düşünüyorsanız varsayımlara itiraz etmek veya düzeltmek için özgürsünüz.


Kaynak 1: Florian Margaine tarafından kruvasanları kimin alacağını bulun.
Kaynak 2: Gilles'in kruvasanlarını kimin alacağını bulun .
Bu soru Gilles'le aynı sürümdür ve farklı toplulukların bir programlama sorununu nasıl ele aldığını görmek için Programcılar üzerinde bir deneme olarak yeniden yayınlanmıştır.


2
Mesaj bildirimi eklendi, gerekirse koruyacağım ama olabildiğince uzun süre açık tutmak istiyorum. Bu sorunun herhangi bir şekilde farklı olmasıyla ilgili olarak, bir deneydir. Açık kalacak. Bilim için!
Dünya Mühendisi

4
Code Golf için daha uygun mu?
ozz

3
Kimin umrunda? Kendine saygılı hiçbir ekipte kruvasan olmazdı. Şimdi, çörek , diğer taraftan, bu ilginç bir soru.
Ross Patterson

3
Bu DA Form 6 için mükemmel bir kullanım örneği gibi görünüyor (heck, 1974'ten beri Ordu için çalışıyor!). Kullanım için AR 220-45'e bakınız. Bunu bir algoritmaya çevirmek nispeten basit olmalıdır.
Adam Balsam

2
(@AdamBalsam form genişletmek için armypubs.army.mil/eforms/pdf/A6.PDF ve kullanım apd.army.mil/pdffiles/r220_45.pdf ... ve benim eski işveren bu önermek etmeyiniz, onlar olduğu gibi yeterli politikalara ve prosedürlere sahip)

Yanıtlar:


26

Bir puanlama algoritması kullanırdım. Her insan sıfır puanla başlar. Her kruvasan getirdiklerinde puanlarını 1 arttırırlar. Kruvasan getirmeyen tüm takım üyelerinin puanı 1 / N azalır. Dolayısıyla, 0 puanı, bir takım üyesinin ne fazla ne de fazla satın alınmadığı anlamına gelir.

Rasgelelik olmadan, mevcut olanlar listesinden en düşük puanı alan kişiyi seçin.

Rasgelelik eklemek için listeyi puana göre sıralayın ve negatif skorlu tüm takım üyeleri arasından rasgele seçin. Negatif puanlarla kısıtlayarak, hiç kimsenin haftalarca çok "şanslı" olmamasını sağlarsınız.

Bu algoritmanın avantajı, tarihsel kayıtları tutmaya dayanması ve herhangi bir zamanda yeni ekip üyelerinin eklenmesine kolayca izin vermesidir.

Sadece kruvasanların tadını çıkarmak için mevcut olanların puanlarını azaltarak devamsızlıkların nispeten yaygın olmasına izin verecek şekilde uyarlanabilir.


3
Son paragrafınızın gerekli olduğunu düşünüyorum, aksi takdirde bir ay boyunca tatile giden biri (belki balayı) büyük bir negatif puana ve çok fazla satın almaya geri dönecekti.
James

8
Ayrıca tweak olabilir: -1 başka birinin getirdi bir pasta yemek. (N-1) hamur işleri alırsanız. Birisi şanslıysa ve sadece 4 için satın alırsa, ertesi gün kişi şanssızlaşır ve 7 için satın alırsa, bu iki satın alma eşit muamele görmez. -1 çünkü kendiniz için satın aldığınız bir hamur işi tarafsızdır.
James

@ James, korku yok; OP ABD'de ve ABD'de hiç kimse bu kadar tatile yakın bir yere ulaşamıyor. :(
Kyralessa

@ James Evet, bu iyi bir gelişme.
Robot Gort

7

Bunu yapmak zorunda kalsaydım, bir şapka almak ve herkesin isimlerini bir kez küçük kağıtlara şapkaya koymak olurdu. Sonra her gün birisinin adını şapkadan rastgele çizerdim ve ertesi gün kruvasanları getiren kişi budur. Bu yazı daha sonra bir tahtada "CROISSANTS TOMORROW GELECEK" altında ele geçirilir. Şu anda tahtada olan kağıt atılır.

Bir de kutum olurdu. Boş başlar. Her gün, isimleri çizmeden önce, kutunun içeriğini şapkaya döktüm, sonra şapkadaki kağıtları geçirdim ve yarın olmayacak herkesi çıkarırdım. İsimleri kutuya giriyor.

Bir isim çizme zamanı gelmişse ve şapka boşsa, biraz daha kağıt yırtıp herkesin adını bir kez eklerdim, sonra yarın olmayacak olan herkesin isimlerini kutuya taşırdım.

Bu son iki adımdan dolayı, aynı adın aynı anda birden fazla kez şapkada olması mümkündür. Çizdiğim isim tahtadaki adla aynıysa, o kağıdı kutuya taşır ve sonra tekrar çizerdim.

Bu sistemi kendi dilinizde bir algoritmaya çevirmek çok zor olmamalıdır.


Dışarı çıkacak herkes için şapkadan ayırmak gerçek bir acı gibi görünüyor.
Bobson

@Bobson: Soru, ekibin büyüklüğünün nispeten küçük olduğunu söylüyor. Büyük bir veri kümesiyle uğraşsaydım, daha karmaşık bir şey yapardım.
Mason Wheeler

6

Algoritma, smalgoritma. Bir DB kullanın.

create table team_members 
(
    id integer auto_increment,
    name varchar(255),
    purchase_count integer,
    last_purchase_date datetime,
    present integer,
    prefers_donuts integer default 0,
    primary key( id)
)

Kim satın alıyor?

select id from team_members where (present = 1) and (prefers_donuts = 0) order by purchase_count, last_purchase_date limit 1;

Satın aldıktan sonra:

update team_members set purchase_count = purchase_count + 1, last_purchase_date = now() where id = ?

Ve sonra ayarlayın:

insert into team_members (name, prefers_donuts) values ('GrandmasterB', 1);

... çünkü ben eski okulum.

İlk sorguyu değiştirerek biraz rasgelelik eklemek çok zor olmamalı - belki last_purchase tarihine göre sıralamak yerine rasgele () ekleyerek.


1
+1. Yeni işe alımlar için, purchase_countdiğer herkesin ortalamasına başlangıç yapıyor musunuz?
Dan Pichelman

6
Hmm, çok güzel bir soru. Muhtemelen işe yarar. Ya da yeni adamı yakalayana kadar her sabah kruvasan getirmesini sağlayabilirsiniz. Ne de olsa o yeni adam.
GrandmasterB

4

Aslında bu problemi gerçek dünyada bir şekilde çözmek zorunda kaldım:

remember how many times people have gotten donuts
every day:
  var candidates = everyone
  toss out people who aren't here tomorrow
  toss out people who aren't here today 
  toss out the person who got them today (unless they're the only one left)
  toss out everyone where "times they got donuts"/"times everyone has got donuts"
    is more than 1/number of people (unless that would eliminate everyone)

  pick someone at random from the candidates

"Çok fazla" çörek satın alan insanlar (kötü şans nedeniyle, diğerleri tatildeyken işe gidecekler, vb.) alımları.

Yine de yeni insanlarla çalışmayı daha iyi idare etmek için genişletilmesi gerekecek ...

Her neyse, bu tasarım değişkenleri değiştirmek için (kimin içinde, kimin dışında) ve programın (pratik olarak) sonsuz olması gerektiğinde gerçekten iyi çalıştı. Ek bir bonus olarak, RNG'nizi ekleyerek deterministik yapmak kolaydır.


2

Zaten sunulan diğer cevapların bazıları kadar iyi değil, ama soruna bakmanın başka bir yolu:

  1. Tüm katılımcı çalışanların bir listesini yapın
  2. Listeyi birçok kez çoğaltın (örneğin, 1.000)
  3. Listeyi karıştır

Her öğleden sonra bir sonraki kruvasan getiriciyi seçin. Her sabah, kruvasan getirici adını listenin en üstünden geçer.

Günlük işleme kalem ve kağıt basittir.

Yeni İşe Alma ve Fesih Mezunlar muhtemelen en iyi şekilde yeni bir liste yapılarak ele alınacaktır. CPU döngüleri tekrar pahalılaşırsa (veya 100M çalışanınız ve sadece 1. nesil Arduino'nuz varsa), orijinal listeyi uygun sayıda yer tutucusuyla tuzlandırmak kolay olurdu.


Daha fazla bilgi (istek başına).

Bu yaklaşımı keyfi olarak uzun bir listeyle kullanarak şeffaflıktan faydalanırsınız.

Sadece yarın kruvasanları kimin getireceğini bilmekle kalmaz, ertesi gün onları kimin getireceğini de bilirsiniz. Tabii ki zamanla daha fazla dışarı çıktığınızda, devamsızlık vb.

Şapkalı kağıt kâğıtlarını nasıl ağırlıklandıracağını anlayan sinsi geliştiriciler, kruvasan getirme görevlerinden kaçınmak için çok fazla fırsata sahip olmayacaklar.

İşlenenlerin hileli olduğunu iddia eden geliştiricilerin sızlanması, verileri kolayca gözden geçirebilir, yanlış sonuç çıkarabilir ve yine de sızlanabilir.


1
Fesihler ? Ghenghis Han bu yazıyı onayladı.
Deer Hunter

1
@DeerHunter İK'nın "insanları sonlandırmak" konusundaki konuşma şeklinden her zaman hoşlanmadım. İş mangalarını akla getiriyor. Belki de onun yerine "Yeni İşe Alım & Mezunlar ..." demeliydim.
Dan Pichelman

1

Rastgele olmayan

Sıralı bir liste bulundurun. Bir kişi satın alması gereken günde yoksa, bir sonraki müsait kişiyle değiştirin. Sonunda kişi mevcut olacak ve böylece kruvasan satın alacak. Bu nedenle, listenin içeriği aynı kalır, ancak kişiler kayıplara bağlı olarak yukarı veya aşağı hareket ettirilebilir.

Geçerli konumdan sonra yeni kişiler listeye eklenir. İşten ayrılan veya feshedilen kişiler listeden çıkarılır. Mevcut konum her gün 1 artar, sona ulaştığında başlangıca geri döner.

Bu, listede adaleti teşvik etmek için ortalama eksiklik süresini hesaba katacak yeterli kişinin olduğunu varsayar.

rasgele

Kısa vadeli önyargı olacağı için her gün rastgele insanları seçemeyiz, örneğin 10 kez bozuk para çevirin ve kafaları 8 ve kuyrukları 2 yükseltebilirsiniz, böylece kafalar kısa vadede vidalanır. Bu yüzden, adil tutmak için insan kovaları oluşturmamız gerekiyor.

Kova, geçmişte insanların çapraz geçiş satın alma sayısına göre belirlenir. Yani, bu durumda, insanların ve çapraz alımların sözlüğünü saklayacağız. 1. günde herkes kova sıfırında. İnsanlar kruvasan alırken, bir sonraki kovaya, yani 1, 2'ye, vs. atanacaklar. Rastgele kısım, kovadaki mevcut insan havuzundan toplanıyor. Mevcut ilk kova, en az satın alan kovadır. Kovada 10 kişi varsa, 1'den 10'a ve kruvasan satın alan rastgele bir sayı seçin. Yeni insanlara en düşük akım kovası atanır, böylece ekstra mermi turları almazlar (hemen hemen satın alma havuzunda olacaklar). En alt kovada kimse yoksa (hepsi yoktur), bir sonraki en yüksek kovaya gidersiniz. Örneğin, Diyelim ki 10 kişilik bir liste var. 8. günde, kova 1'de ve 8 kova 0'da 8 kişi bulunur. Kova 0'da iki kişi yoktur. Bu durumda, kova 1 kullanılır ve bir kişi kova 2 ile sonuçlanır. Ancak, insanlar her zaman kendi içinde birkaç çapraz satın alma (kova) içinde olacaktır, çünkü şimdi kova 2'deki kişi büyük olasılıkla içinde olmayacaktır. bir süre satın havuzu.

Aynı kişinin arka arkaya iki gün satın almadığından emin olmak için ince ayarlar eklenebilir ve ele alınması gereken bazı kenar durumlar vardır, ancak bu, rastgele kalmanın yanı sıra rastgele bir öğe ekler. Ayrıca, gerçek kruvasan alımlarını mevcut kovaya karşı ayrı tutmak isteyebilirsiniz. İnsanlar giderken kovadan kalıcı olarak yok olarak işaretleyerek veya tamamen silerek kovadan çıkarılır.


1
Rastgele uygulama eklendi.
Jon Raynor
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.