找出可能要去买羊角面包的人,


13

一个团队决定每天早上有人应给每个人带羊角面包。每次都不应该是同一个人,因此应该有一个系统来确定下一个轮到谁。这个问题的目的是确定一种算法,以确定明天将把羊角面包带给谁。

约束,假设和目标:

  • 谁来带羊角面包将在前一天下午确定。
  • 在任何一天,都会有人不在。该算法必须选择当天要出席的人。假设所有缺勤都是提前一天知道的,因此可以在前一个下午确定新月形面包的购买者。
  • 总体而言,大多数人都在大多数时间都在场。
  • 为了公平起见,每个人都应该购买羊角面包,其次数应与其他人一样多。(基本上,假设每个团队成员都有相同数量的钱用于羊角面包。)
  • 为了减轻花名册的无聊感,最好具有一些随机性或至少感知到的随机性。这不是一个硬性约束:它更多是一种审美判断。但是,同一个人不应连续两次被选中。
  • 带羊角面包的人应该事先知道。因此,如果人P在D日带上羊角面包,那么应该在人P出现的前一天确定这一事实。例如,如果总是在前一天确定了羊角面包的携带者,那么应该是前一天在场的人之一。
  • 团队成员的数量足够少,以至于存储和计算资源实际上是无限的。例如,该算法可以依靠过去曾带谁羊角面包的完整历史记录。每天在快速PC上进行几分钟的计算就可以了。

这是一个现实问题的模型,因此,如果您认为这些假设可以更好地模拟场景,则可以自由挑战或完善这些假设。


起源1:找出谁要购买 Florian Margaine 的羊角面包
起源2:找出谁打算购买 Gilles 的羊角面包
这个问题与Gilles的版本相同,已作为实验重新发布在Programmers上,以查看不同社区如何应对编程挑战。


2
添加了公告功能,如果需要的话,我会提供保护,但我会尽可能长时间保持开放。关于这个问题无论如何,这是一个实验。它将保持打开状态。为了科学!
世界工程师

4
更适合Code Golf?
ozz

3
谁在乎?没有自尊心的团队会有羊角面包。现在,另一方面,甜甜圈是一个有趣的问题。
罗斯·帕特森

3
这听起来像是DA Form 6的完美用例(哎呀,自1974年以来就为陆军工作了!)。有关用法,请参见AR 220-45。将其转换为算法应该相对简单。
亚当·巴尔萨姆

2
(要在@AdamBalsam上展开,格式为Armypubs.army.mil/eforms/pdf/A6.PDF和用法apd.army.mil/pdffiles/r220_45.pdf ...,请不要向我的前任雇主建议,拥有足够的策略和过程)

Answers:


26

我会使用评分算法。每个人的得分都从零开始。每次他们携带羊角面包时,将其得分增加1。未携带羊角面包的所有团队成员的得分将减少1 / N。因此,分数为0表示团队成员既没有买过也没有买过。

在没有随机性的情况下,从要出席的人员列表中选择得分最低的人员。

要增加随机性,请按分数对列表进行排序,然后从所有分数为负的团队成员中随机选择。通过限制分数为负数,可以确保在许多星期内没有人会太“幸运”。

该算法的优势在于它不依赖于保留历史记录,并且可以轻松地在任何时间点添加新的团队成员。

可以通过减少只享用羊角面包的人的分数来适应缺席的情况。


3
我认为您的最后一段是必不可少的,否则度假一个月(也许是蜜月)的人会回来获得巨大的负分和大量购买。
詹姆斯

8
还可以调整:如果您吃别人带的糕点,则为-1。(N-1),如果您购买糕点。这样,如果某人幸运并仅以4的价格购买,那么第二天该人不幸并以7的价格购买,这两次购买没有得到平等对待。-1,因为您自己购买的糕点是中性的。
詹姆斯

@詹姆斯,不用害怕;OP在美国,而在美国,没有人能得到那么多的假期。:(
Kyralessa

@James是的,这是一个很好的改进。
毁灭了机器人

7

如果我必须选这个,我会做的就是戴上帽子,然后将每个人的名字放在帽子上,放在小纸片上。然后,每天我都会从帽子上随机取一个人的名字,那是第二天带来羊角面包的人。然后,将该文件粘贴到板上的“ BRINGING CROISSANTS TOMORROW”下。当前板上的纸张被扔掉了。

我还要一个盒子。它开始是空的。每天,在画出名字之前,我都会把盒子里的东西倒进帽子里,然后翻遍帽子里的文件,搬走明天要缺席的所有人。他们的名字在框中。

如果是时候画一个名字并且帽子是空的,我会撕碎一些纸,并给每个人添加一次名字,然后将明天将要缺席的每个人的名字移到盒子里。

由于这最后两个步骤,同一个名字可能一次出现多次。如果我要绘制的名称与黑板上的名称相同,则将纸张移到盒子中,然后再次绘制。

将系统转换为您选择的语言的算法并不难。


为将要出去的每个人整理帽子似乎是一种真正的痛苦。
Bobson

@鲍勃森:这个问题专门说团队规模相对较小。如果要处理大型数据集,我会做一些更复杂的事情。
梅森·惠勒2013年

6

算法,算法。使用数据库。

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

...因为我是老学校。

通过调整第一个查询来增加一些随机性应该不是很困难-也许可以添加一个random()而不是按last_purchase日期进行排序。


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. 随机排列列表

每天下午,选择下一个可用的新月形面包。每天早晨,新月形面包匠将他/她的名字从列表的顶部移开。

日常处理非常简单。

新的雇用和终止校友可能最好通过列出新清单来处理。如果CPU周期再次变得昂贵(或者您有1亿员工并且只有第一代Arduino),那么可以很容易地用适当数量的占位符添加原始列表。


更多信息(按请求)。

通过将这种方法与任意长的列表一起使用,可以获得透明性的好处。

您不仅知道明天谁将带给羊角面包,而且知道第二天又将带给谁。当然,时间越远,由于缺席等原因,您看起来越不准确。

鬼how的开发人员想出了如何在帽子上增加纸片重量的方法,将没有太多的机会来避免承担羊角面包的工作。

声称已处理已操纵的非开发人员会发牢骚,可以轻松地查看数据,得出错误的结论并仍然发牢骚。


1
终止?Ghenghis Khan批准了此职位。
Deer Hunter

1
@DeerHunter我一直不喜欢HR谈论“终止人员”的方式。它使我想到了解雇小队。也许我应该说“ New Hires&Alumni ...”。
Dan Pichelman

1

非随机

维护有序列表。如果某人在应该购买的日期缺席,请与下一位有空的人交换。最终,此人将在场,然后购买羊角面包。因此,列表的内容保持不变,但是根据缺席情况,人员可能会上下移动。

新人员会插入到当前职位之后的列表中。退出或终止的人将从列表中删除。当前位置每天增加1,到达终点时,它将回到起点。

假设列表中有足够的人来说明平均的缺勤时间以促进公平。

随机

我们不能每天选择随机的人,因为会有短期偏见,例如掷硬币10次,您可能会抬头8,而尾巴2,因此短期内头会被拧紧。因此,我们需要创建很多人来保持公平。

金额取决于人们过去购买商品的次数。因此,在这种情况下,我们将存储有关人员和交叉购买的字典。在第一天,每个人都处于零桶状态。当人们购买羊角面包时,它们将被分配到下一个存储桶中,即1、2等。随机部分是从存储桶中的可用人员中选择的。第一个可用的存储桶是购买量最少的存储桶。如果存储桶中有10个人,则从1到10中随机选择一个,然后购买新月形面包。新员工被分配了当前最低的费用,因此他们最终不会购买额外的交叉攻击(尽管他们将立即进入购买池)。如果最低的存储桶中没有一个可用的存储桶(它们都不存在),则转到下一个最高的存储桶。例如,让我们 s说有一个10个人的名单。在第8天,存储桶1中有8个人,存储桶0中有2个人。存储桶0中的两个人都不存在。在这种情况下,将使用存储桶1,一个人最终将进入存储桶2。但是,人们之间总是会相互进行一些交叉购买(存储桶),因为现在处于存储桶2中的人很可能不在其中购买池一段时间。

可以添加一些调整来确保同一个人连续两天不买东西,并且要处理一些极端情况,但这会增加随机性并保持公平性。另外,可能希望将实际的羊角面包购买量与当前的购买量分开。当人们离开时,可以通过将其永久标记或完全删除来从存储桶中删除。


1
添加了随机实现。
乔恩·雷诺
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.