결석 가능성을 설명하고 크루아상을 구매하는 사람이 누구인지 확인하십시오.


13

한 팀은 매일 아침 누군가를 위해 크루아상을 가져와야한다고 결정했습니다. 매번 같은 사람이되어서는 안되므로 다음 차례를 결정하는 시스템이 있어야합니다. 이 질문의 목적은 내일 크로와상을 가져올 차례를 결정할 알고리즘을 결정하는 것입니다.

제약, 가정 및 목표 :

  • 크루아상을 가져 오는 것이 누구의 차례인지 전날 오후에 결정됩니다.
  • 어느 날, 어떤 사람들은 결석합니다. 알고리즘은 그 날에 참석할 사람을 선택해야합니다. 모든 결석을 하루 전에 미리 알고 있다고 가정하면 크루아상 구매자는 이전 오후에 결정할 수 있습니다.
  • 전반적으로 대부분의 사람들은 대부분의 날에 참석합니다.
  • 공정성을 위해 모든 사람은 다른 사람보다 크루아상을 구입해야합니다. 기본적으로 모든 팀원은 크루아상에 쓸 돈이 같다고 가정합니다.
  • 명단의 지루함을 완화하기 위해 임의의 요소 또는 적어도 인식 된 임의성을 갖는 것이 좋을 것입니다. 이것은 어려운 제약이 아닙니다 : 심미적 인 판단에 가깝습니다. 그러나 같은 사람을 연속으로 두 번 선택해서는 안됩니다.
  • 크로와상을 가져 오는 사람은 미리 알아야합니다. 따라서 P 개인이 D 일에 크로와상을 가져 오려면 P 개인이있는 전날에이 사실을 결정해야합니다. 예를 들어, 크루아상 가져 오는 사람이 항상 전날 결정되면, 그것은 전날에 참석 한 사람 중 한 사람이어야합니다.
  • 팀원의 수는 스토리지 및 컴퓨팅 리소스가 사실상 무제한이 될 정도로 적습니다. 예를 들어, 알고리즘은 과거에 크루아상을 가져온 사람의 완전한 역사에 의존 할 수 있습니다. 빠른 PC에서 매일 최대 몇 분 동안 계산해도 괜찮습니다.

이것은 실제 문제의 모델이므로 시나리오를 더 잘 모델링한다고 생각되면 가정에 자유롭게 이의를 제기하거나 구체화 할 수 있습니다.


Origin 1 : Florian Margaine 의 크로와상을 구매할 사람을 찾으십시오 .
Origin 2 : Gilles 의 크로와상을 구매할 사람을 알아보십시오 .
이 질문은 Gilles와 같은 버전이며, 다른 커뮤니티가 프로그래밍 문제를 해결하는 방법을보기위한 실험으로 프로그래머에게 다시 게시되었습니다.


2
게시물 통지를 추가하면 필요한 경우 보호하지만 최대한 오래 열어두고 싶습니다. 이 질문이 어떤 식 으로든 어려운 점에 대해서는 실험입니다. 열린 상태로 유지됩니다. 과학을 위해!
세계 엔지니어

4
코드 골프에 더 적합합니까?
ozz

3
무슨 상관이야? 자존심있는 팀은 크루아상을 갖지 않습니다. 이제, 도넛 , 다른 한편으로는, 그 흥미로운 질문이다.
로스 패터슨

3
이것은 DA Form 6의 완벽한 유스 케이스처럼 들립니다 (1974 년 이후 육군에서 근무했습니다!). 사용법은 AR 220-45를 참조하십시오. 이를 알고리즘으로 변환하는 것은 비교적 간단해야합니다.
Adam Balsam

2
(@AdamBalsam에 양식 확장하는 armypubs.army.mil/eforms/pdf/A6.PDF 및 사용 apd.army.mil/pdffiles/r220_45.pdf을 ... 내 전 고용주에게이 제안하지 마십시오, 그들이 충분한 정책과 절차가있는 경우)

답변:


26

점수 알고리즘을 사용합니다. 각 사람은 0 점으로 시작합니다. 크루아상을 가져올 때마다 점수가 1 씩 증가합니다. 크루아상을 가져 오지 않은 모든 팀원의 점수는 1 / N 감소합니다. 따라서 0 점은 팀원이 초과 또는 미달 구매를하지 않았 음을 의미합니다.

무작위성이 없으면 출석 할 사람들 중에서 가장 낮은 점수를받은 사람을 선택하십시오.

임의성을 추가하려면 점수별로 목록을 정렬하고 음수 점수를 가진 모든 팀 구성원 목록에서 임의로 선택하십시오. 음수 점수로 제한하면 몇 주 동안 아무도 "운이 좋은"사람이되지 않습니다.

이 알고리즘의 장점은 기록을 유지하는 데 의존하지 않으며 언제든지 새로운 팀원을 쉽게 추가 할 수 있다는 것입니다.

크루아상을 즐기기 위해 존재하는 사람들의 점수를 줄임으로써 부재가 상대적으로 흔하도록 허용 할 수 있습니다.


3
나는 마지막 단락이 필수적이라고 생각합니다. 그렇지 않으면 한 달 동안 휴가를 보낸 사람 (신혼 여행)은 엄청난 부정적인 점수와 많은 구매로 돌아올 것입니다.
James

8
다른 사람이 가져온 과자를 먹으면 -1도 조정할 수 있습니다. 파이를 사면 (N-1). 그렇게하면 누군가가 운이 좋아서 4 명만 사면 다음날 그 사람이 불운 해져 7을 사면된다. -1 자신이 직접 구매 한 과자는 중립적입니다.
James

@ 제임스, 두려움 없음; OP는 미국에 있으며 미국의 어느 누구도 그처럼 많은 휴가를 보내지 않습니다. :(
Kyralessa

@ 제임스 그래, 그것은 좋은 개선입니다.
로봇

7

내가 이것을 선택해야한다면, 모자를 쓰고, 작은 종이에 모든 사람의 이름을 모자에 넣으십시오. 그런 다음 매일, 나는 모자에서 누군가의 이름을 무작위로 뽑았습니다. 그리고 그것은 다음 날 크로와상을 가져 오는 사람입니다. 그런 다음 "BRINGING CROISSANTS TOMORROW"아래에 종이에 붙입니다. 현재 보드에있는 종이는 버려집니다.

나는 또한 상자를 가질 것이다. 빈 상태로 시작합니다. 매일 이름을 그리기 전에 상자의 내용물을 모자에 버린 다음 모자에있는 서류를 살펴보고 내일 결석 할 사람을 모두 제거합니다. 그들의 이름은 상자에 들어갑니다.

이름을 그릴 시간이고 모자가 비어 있다면 종이를 더 찢어서 모든 사람의 이름을 한 번 추가 한 다음 내일 결석 할 모든 사람의 이름을 상자로 옮기십시오.

이 마지막 두 단계로 인해 같은 이름이 한 번에 여러 번 모자에있을 수 있습니다. 내가 그리는 이름이 칠판에 적힌 이름과 같으면 그 종이를 상자로 옮긴 다음 다시 그립니다.

이 시스템을 원하는 언어로 알고리즘으로 변환하는 것은 어렵지 않습니다.


외출하려는 모든 사람들을 위해 모자를 정렬하는 것은 진짜 고통처럼 보입니다.
밥슨

@ 밥슨 : 문제는 구체적으로 팀의 규모가 상대적으로 작다는 것을 나타냅니다. 대규모 데이터 세트를 다루는 경우 더 정교한 작업을 수행합니다.
메이슨 휠러

6

알고리즘, 작은 알고리즘. DB를 사용하십시오.

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

누가 사나요?

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

그들이 구매 한 후 :

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

그런 다음 설정하십시오.

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

... 오래된 학교이기 때문에.

첫 번째 쿼리를 조정하여 last_purchase 날짜로 정렬하는 대신 random ()을 추가하여 약간의 무작위성을 추가하는 것은 너무 어렵지 않아야합니다.


1
+1. 신입 사원의 경우 purchase_count다른 모든 사람의 평균으로 초기화 합니까?
Dan Pichelman

6
흠, 아주 좋은 질문입니다. 아마도 효과가있을 것입니다. 또는 새로운 남자가 매일 아침에 크로와상을 가져 오게 할 수 있습니다. 그는 결국 새로운 사람입니다.
GrandmasterB

4

실제로이 문제를 실제로 해결해야했습니다.

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

도넛을 "너무 많이"구입 한 사람들 (불운, 다른 사람들이 휴가 중일 때 등으로 인해 일을하는 등)은 충분한 인수를 통해 도넛을 "오른쪽"퍼센트 아래로 되돌릴 때까지 풀에서 제외됩니다. 구매.

그래도 신입 사원 채용을 더 잘 처리하려면 확장해야합니다 ...

어쨌든,이 디자인은 변수를 변경 (누가 있는지, 누가 있는지)하고 일정이 (실제로) 무한해야 할 때 실제로 잘 작동했습니다. 추가 보너스로 RNG를 시드하여 결정론을 쉽게 만들 수 있습니다.


2

이미 제시된 다른 답변만큼 좋지는 않지만 문제를 보는 또 다른 방법은 다음과 같습니다.

  1. 참여하는 모든 직원의 목록을 작성하십시오.
  2. 목록을 여러 번 복제 (예 : 1,000)
  3. 목록 섞기

매일 오후, 다음 크로와상 자르기를 선택하십시오. 매일 아침 크로와상은 목록의 맨 위에서 이름을 es니다.

일일 처리는 펜 및 종이로 간단합니다.

새로운 고용 및 해지 동창생은 새로운 목록을 작성함으로써 가장 잘 처리 될 것입니다. CPU 사이클이 다시 비싸 질 경우 (또는 1 억 명의 직원과 1 세대 Arduino 만 있음) 적절한 수의 자리 표시 자로 원래 목록을 작성하는 것이 쉽습니다.


추가 정보 (요청 당).

임의로 긴 목록과 함께이 방법을 사용하면 투명성의 이점을 얻을 수 있습니다.

내일 크루아상을 가져올 사람을 알고있을뿐만 아니라 다음 날 누가 가져갈 예정인지 등을 알 수 있습니다. 물론 시간이 지날수록 결근 등으로 인해 정확도가 떨어집니다.

모자에 종이 미끄러짐을 달아 넣는 방법을 알아내는 비열한 개발자들은 크로와상 양육 의무를 피할 기회가 많지 않습니다.

처리 된 장비가 조작되었다고 주장하는 비 개발자는 데이터를 쉽게 검토하고 잘못된 결론을 내릴 수 있습니다.


1
종료 ? Ghenghis Khan이이 게시물을 승인합니다.
사슴 사냥꾼

1
@DeerHunter 저는 HR이 "종료"에 대해 말하는 방식을 항상 싫어했습니다. 사격팀을 생각 나게합니다. 어쩌면 나는 "New Hires & Alumni ..."라고 말했을 것입니다.
Dan Pichelman

1

무작위가 아닌

정렬 된 목록을 유지하십시오. 구매할 날에 결석 한 사람이 있으면 사용 가능한 다음 사람과 교환하십시오. 결국 그 사람은 참석하여 크루아상을 구입할 것입니다. 따라서 목록의 내용은 동일하게 유지되지만 결석에 따라 사람이 위 또는 아래로 이동할 수 있습니다.

현재 위치 다음에 새로운 사람들이 목록에 삽입됩니다. 종료하거나 종료 한 사람들은 목록에서 제거됩니다. 현재 위치는 매일 1 씩 증가하며 끝에 도달하면 시작 위치로 돌아갑니다.

이것은 공정성을 촉진하기 위해 평균 결근 시간을 설명하기에 충분한 사람들이 목록에 있다고 가정합니다.

무작위

단기 바이어스가있을 때마다 무작위로 사람들을 선택할 수는 없습니다. 예를 들어 동전을 10 번 뒤집 으면 머리 8과 꼬리 2가 나타날 수 있으므로 단기적으로 머리가 망칠 수 있습니다. 그래서 우리는 사람들을 공정하게 유지하기 위해 버킷을 만들어야합니다.

버킷은 과거 사람들이 Crossiants를 구매 한 횟수에 의해 결정됩니다. 따라서이 경우, 사람들의 사전과 Crossiant 구매를 저장합니다. 1 일째에 모든 사람이 버킷 제로에 있습니다. 사람들이 크로와상을 구매할 때 다음 버킷에 할당됩니다 (예 : 1, 2 등). 무작위 부분은 버킷에있는 사용 가능한 사람들의 풀에서 선택됩니다. 가장 먼저 구매할 수있는 버킷은 구매 횟수가 가장 적은 버킷입니다. 버킷에 10 명이있는 경우 1에서 10 사이의 임의의 숫자와 크루아상을 사는 사람을 선택하십시오. 새로운 사람들에게는 가장 낮은 현재 버킷이 할당되므로 추가 라운드의 Crossiants를 구매하지 않아도됩니다 (구매자는 즉시 구매 풀에 있음). 가장 낮은 버킷에 아무도 없을 경우 (모두 없음) 다음으로 가장 높은 버킷으로 이동합니다. 예를 들어 10 명의 사람들이 있다고한다. 8 일에는 버킷 1에 8 명이 있고 버킷 0에 2 명이 있습니다. 버킷 0에 2 명이 없습니다. 이 경우 버킷 1이 사용되고 한 사람이 버킷 2에있게됩니다. 그러나 현재 버킷 2에있는 사람은 대부분 버킷 2에 속하지 않을 가능성이 높기 때문에 사람들은 서로간에 몇 개의 교차 구매 (버킷) 내에있게됩니다. 잠시 동안 구매 수영장.

같은 사람이 연속해서 이틀을 사지 않고 처리해야 할 몇 가지 사례가 있는지 확인하기 위해 조정을 추가 할 수 있지만, 이것은 임의의 요소를 추가하고 공정하게 유지합니다. 또한 실제 크루아상 구매와 현재 버킷을 분리하여 유지하고 싶을 수도 있습니다. 사람들이 떠날 때 버킷에서 영구적으로 결석을 표시하거나 모두 삭제하여 버킷에서 제거됩니다.


1
랜덤 구현이 추가되었습니다.
Jon Raynor
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.