理发师的难题

机器算法验证 正态分布 优化 排队 决策理论
2022-03-26 05:09:49

我的理发师 Stacey 总是装出一副幸福的表情,但经常强调如何管理她的时间。今天斯泰西迟到了我的约会,非常抱歉。理发时,我想知道:她的标准约会应该多长时间?(如果可以暂时忽略客户对干净整数的偏好)。

需要考虑的是某种“涟漪效应”,一个很晚的客户可能会导致一连串的预约延迟。实际上,由于害怕这些压力日,美发师直觉地学会了将约会的间隔时间越来越长。但是一个最佳的,优雅的解决方案必须由一些统计天才来实现..(如果我们稍微降低现实)

让我们假设

a) 剪发时间呈正态分布,并且

b) 只有一个美发师。

预约时间过长的成本显然是浪费了美发师等待下一次预约的时间。让我们每分钟花费 1 美元。

但如果预约时间不够长,下一位顾客就会一直等待,这对于热爱顾客的 Stacey 来说是每分钟 3 美元的成本。

  • Stacey 每天工作长达 8 小时,并且有足够的需求,她可以满足尽可能多的约会

  • 平均理发需要她 30 分钟,有性病。开发 10 分钟。(我们还假设男士剪裁和女士剪裁相同!)

编辑 - 有些人正确地指出,Stacey 可以在他们指定的时间之前照顾早期客户。这增加了另一层复杂性,但如果我们将其视为一个非常现实的问题,我们需要将其包括在内。让我们忘记我的 90/10 假设,尝试一个可能更接近现实的假设。

  • 有些顾客迟到,有些顾客早到。顾客的平均迟到 2 分钟,标准差为 2 分钟(听起来很接近现实,不是吗?)

她的约会到底应该多长时间?


@alexplanation 抱歉,我已将球门柱移到你身上!我相信 R 读者会欣赏你的回答。

1个回答

这个问题有很多活动部分,这使得它适合模拟。

首先,正如猫王在评论中提到的那样,斯泰西似乎应该预约 16 次,因为每次约半小时。但是你知道,随着约会开始延迟,事情开始变得越来越晚——所以如果 Stacey 只在她还有半个小时的时候才开始约会(扫地的头发就这么多了,嗯,Stacey ?) 如果我们使用水晶球来安排没有休息时间的约会,那么我们将有少于 16 个可能的空档。

最佳间隔理发

在下一个模拟中,我们可以研究成本曲线作为预约时间的函数。当然,其余参数最终也会在这里发挥作用——实际上,Stacey 不会安排她的约会相隔几分钟,但这让我们对正在发生的事情有了一些直觉。

在此处输入图像描述

我还绘制了 Stacey 必须作为颜色工作的时间。我决定 Stacey 永远不会在 7:30 之后安排她的最后一次约会,但有时约会会迟到,或者有延迟!你可以看到她回家的时间是量化的,所以随着约会的时间变长,你会少一个约会,然后就不必工作到很晚了。而且我认为这是这里缺少的元素-也许安排您的约会相隔 45 分钟很好,但是如果您可以将其压缩到 40 分钟,您将获得额外的约会。该成本已包含在 Stacey 的等待中(这就是成本上涨的原因随着约会时间的延长而增加),但您对 Stacey 等待时间的估计可能不正确。

无论如何,有趣的问题!并且是学习一些 ggplot 优点并记住我的 R 语法非常不稳定的好方法。:)

我的代码如下 - 请随时提供改进建议。


要生成顶部图的代码:

hairtime = 30
hairsd = 10

nSim = 1000
allCuts = rep(0,nSim)
allTime = rep(0,nSim)

for (i in 1:nSim) {
    t = 0
    ncuts = 0

    while (t < 7.5) {
        ncuts = ncuts+1
        nexthairtime = rnorm(1,hairtime,hairsd)
        t = t+(nexthairtime/60)
    }
    allCuts[i] = ncuts
    allTime[i] = t
}

hist(allCuts,main="Number of haircuts in an 8 hour day",xlab="Customers")

第二次模拟要长很多...

nSim = 100
allCuts = rep(0,nSim)
allTime = rep(0,nSim)

allCost = rep(0,nSim)

lateMean = 10
lateSD = 3

staceyWasted = 1
customerWasted = 3

allLengths = seq(30,60,0.25)

# Keep everything in 'long form' just to make our plotting lives easier later
allApptCosts = data.frame(matrix(ncol=3,nrow=length(allLengths)*nSim))
names(allApptCosts) <- c("Appt.Length","Cost","Time")
ind = 1

# for every appointment length...
for (a in 1:length(allLengths)) {
    apptlen = allLengths[a]
    # ...simulate the time, and the cost of cutting hair.
    for (i in 1:nSim) {
        appts = seq(from=0,to=(8-hairtime/60),by=apptlen/60)
        t = 0
        cost = 0
        ncuts = 0

        for (a in 1:length(appts)) {
            customerArrival = appts[a]
            # late!            
            if (runif(1)>0.9) {
                customerArrival = appts[a]+rnorm(1,lateMean,lateSD)/60
            }

            waitTime = t-customerArrival
            # negative waitTime means the customer arrives late
            cost = cost+max(waitTime,0)*customerWasted+abs(min(waitTime,0))*staceyWasted
                                        # get the haircut
            nexthairtime = rnorm(1,hairtime,hairsd)
            t = customerArrival+(nexthairtime/60)
        }
        allCost[i] = cost
        allApptCosts[ind,1] = apptlen
        allApptCosts[ind,2] = cost
        allApptCosts[ind,3] = t
        ind = ind+1
    }
}

qplot(Appt.Length,Cost,geom=c("point"),alpha=I(0.75),color=Time,data=allApptCosts,xlab="Appointment Length (minutes)",ylab="Cost")+
      geom_smooth(color="black",size=2)+
    opts(axis.title.x=theme_text(size=16))+
    opts(axis.title.y=theme_text(size=16))+
    opts(axis.text.x=theme_text(size=14))+
    opts(axis.text.y=theme_text(size=14))+
    opts(legend.text=theme_text(size=12))+
    opts(legend.title=theme_text(size=12,hjust=-.2))