马桶座圈算法

时间:2010-01-21 23:06:42

标签: algorithm language-agnostic

我们带一个普通的房子,一个男人,每隔n分钟就要上厕所,要求座位上升,还有一个女人,每隔m分钟就要做一次,要求座位下降。是否有可能创建O(1)算法,该算法将在X分钟的特定时间段内输出准确数量的马桶座圈移动?有两种不同的附加输入:
这名男子在访问后总是离开座位 这位男士在访问后总是把座位放下来。

结论:在现实生活中(涉及n远远超过m,X->无穷大),证明没有区别在许多座位运动中。
但是,如果一个男人经常这样做,那么一个女人,如果他只是离开座位就会延长座位寿命,但在这种情况下,其中一个(或两个)应该去看医生。登记/> 现在我知道座椅本身最好的是什么,但是哪个人做出更多动作 - 是另一个问题(不管怎么说都不应该问)。

5 个答案:

答案 0 :(得分:14)

是的,有一个基本的O(1)算法。

我首先假设两个人在t = 0时开始“滴答”。 我认为解决方案应该概括为不同的起始时间,但不难从时间轴的一个“自由端”扩展到两端。

假设n <= m。

然后我们的时间表看起来像这样('x'表示'移动',而不是访问)

  0     m    2m    ..              t-t%m  t
  +-----+-----+-----+-----+-----+-----+--o
W x     x     x     x     x     x     x 
M x  x    x    x       x     x    x     x?

所以,女人去地板(t / m),然后去 女人每次去 - 半开的时间间隔(a*m,*m+m] -  这个男人至少走了一次,从而翻过座位一次。对于 每次她在一段时间内翻转座位,他也会翻转一次。 但是,他可能会再次去 她的最后一次旅行,取决于他们的相对时间, 您可以根据t模数计算各自的周期。

total_moves = floor(t/m) * 2 + (t%m < t%n ? 1 : 0)

现在针对案例n&gt;米。

女人和男人的角色被颠倒了......半开的间隔 [an, an+n)总是涉及两个动作。剩下的 该行是[t-t%n,t),其中男人在开始时去了一次, (这是+1移动,但我们在t = 0时对两个人的移动计算了+2,我们应该放弃),如果她剩下的时间比他的剩余时间还少,那么女人就会去。

total_moves = floor(t/n) * 2 - 1 + (t%m >= t%n ? 1 : 0)

答案 1 :(得分:7)

对于2,答案是2*floor(X/n)。这个男人总是带着马桶座去洗手间,然后把它放下。女人永远不会爱不释手,因为只有当男人去洗手间时,女人才会放下它。

1有点棘手。

编辑:Duh。对于1,答案是2*floor(X/m)。当女人去洗手间时,马桶座只会过渡。

EDIT2:加上或减去马桶的初始状态。

EDIT3:我对1的回答只有在m>=n时才正确。我稍后会弄清楚剩下的。

EDIT4:如果是n>=2m,那么它是2*floor(X/n),因为座位只会在男人小便时过渡。如果n>m,我相信答案也是2*floor(X/n),但我需要计算出数学。

EDIT5:所以,对于2m>n>m,当男人在女人后面撒尿时,座位会转换,反之亦然。每隔least_common_multiple(m, n)分钟,人/女访问的顺序会重复,因此我们只需要关注那段时间内发生的事情。只有当他设法连续两次访问座位时,座位才会过渡。鉴于该女性经常访问更多,每次男性访问之间至少有一位女性访问。 (开头或结尾两次。)

答案1然后变成:(n>m ? 2*floor(X/n) : 2*floor(X/m)) + (remainder(X/n) > remainder(X/m) ? 1 : 0)。或类似的东西。

答案 2 :(得分:4)

是的,至少在实施时可以假设一个男人和一个女人的周期提前知道并且它没有改变:

从男性/女性周期时间的最小公倍数(lcm)开始。预先计算此时间段的移动(lcm_movements)。现在,您只需要处理输入timelcm。为此,您只需设置一个固定长度的表格,其中包含每分钟的移动次数。

鉴于timelcm是Java / C / C ++ / C#中的整数,实际计算可能是这样的:

return ( time / lcm ) * lcm_movements + movements[ time % lcm ];

答案 3 :(得分:2)

假设:

  • 我们从t = 0开始,马桶座圈朝下
  • 如果男人和女人同时到达,那么先是女士们。

设lastLadyTime:= floor(X / m)* m和lastManTime:= floor(X / n)* n。它们代表了最后一次使用厕所。表达式(lastLadyTime&gt; lastManTime)与(X%m&lt; X%n)相同,因为根据定义X%m = X - lastLadyTime和X%n = X - lastManTime。

案例:男人离开座位
这位女士永远不必移动座位,但他总是需要抬起座位。因此floor(X/n)

案例:男人离开座位,n == m
他总是需要抬起它,除了第一次使用厕所时她总是需要把它推下去,而她不需要做任何事情。因此2*floor(X/n) - (X < n ? 0 : 1)

案例:男人离开座位,n&gt;米
每次他使用它,他都需要抬起它。她只需要在使用它之后将其推倒一次。这种情况一直发生,除非在她开始使用厕所之前时间已经结束。因此,如果lastManTime&gt; = lastLadyTime,我们必须减去1(记住,女士们首先)。因此2 * floor(X / n) - (lastManTime&gt; = lastLadyTime?1:0)= 2*floor(X/n) - (X%n <= X%m ? 1 : 0)

案例:男人离开座位,n&lt;米
与n>相似米每次使用它,她都需要将其推倒。使用后,他只需要抬起一次。这种情况一直发生,除非在他不得不在她之后使用厕所之前用完时间结束。因此,如果lastManTime&lt; lastLadyTime。另外一个区别是他需要第一次抬起座位。因此2 * floor(X / m) - (lastManTime&lt; lastLadyTime?1:0)+(X&lt; n?0:1)= 2*floor(X/m) - (X%n > X%m ? 1 : 0) + (X < n ? 0 : 1)

答案 4 :(得分:0)

如果所有微小变量都是整数,那么你可以这样做:

int toilet_seat_movements = 0;
bool seat_up = false;

for (i = 0; i <= total_minutes; i++)
{
    if (seat_up)
    {
        if (i % woman_minutes == 0)
            toilet_seat_movements++;
    }
    else
    {
        if (i % man_minutes == 0)
            toilet_seat_movements++;
    }
}

return toilet_seat_movements;