【问题标题】:Just for fun - getting started on a tricky PHP logic problem只是为了好玩 - 开始处理一个棘手的 PHP 逻辑问题
【发布时间】:2011-06-18 15:25:35
【问题描述】:

作为提高我作为 PHP 开发人员技能的一种方式,我经常挑战自己来自站点 Programming Praxis 的问题。 99% 的时间我可以自己解决谜题,但我被困在这个谜题上,需要一些关于如何开始的指导。这个谜语叫做“多居”。问题来了:

贝克、库珀、弗莱彻、米勒和史密斯住在一栋只有五层楼的公寓的不同楼层。贝克不住在顶层。库珀不住在底层。弗莱彻既不住在顶层也不住在底层。米勒住在比库珀更高的楼层。史密斯不住在弗莱彻家附近的楼层。弗莱彻不住在库珀附近的地板上。大家都住在哪里?

我的基本问题是:我不明白如何测试和评估不同的逻辑情况。所以举个例子,如果我们要测试贝克是否属于一楼,那么如何最好地为剩下的 4 个人每个人“填写”测试位置?我的(许多)尝试都在巨大的 If/else if/else 树的底部以失败告终。

这不是为了家庭作业、金钱或名声 - 只是一个我可以在开始时需要一点帮助的谜语!

更新 - 这是我的解决方案!感谢大家的所有输入,不一定优化,但至少现在我明白了:

<?php

    function testThisOne ($testList) {
        $MillerFloor = "";
        $CooperFloor = "";
        $SmithFloor = "";
        $FletcherFloor = "";

        foreach ($testList as $key => $person) if ($person == "Miller") $MillerFloor = $key;
        foreach ($testList as $key => $person) if ($person == "Cooper") $CooperFloor = $key;
        foreach ($testList as $key =>$person) if ($person == "Smith") $SmithFloor = $key;
        foreach ($testList as $key => $person) if ($person == "Fletcher") $FletcherFloor = $key;

        if ($testList[4] == "Baker") return false;
        if ($testList[0] == "Cooper") return false;
        if ($testList[0] == "Fletcher" || $testList[4] == "Fletcher") return false;
        if ($MillerFloor < $CooperFloor) return false;
        if (abs($SmithFloor - $FletcherFloor) == 1 || abs($CooperFloor - $FletcherFloor) == 1) return false;

        return true;
    }

    function puzzleSolve1() {
        $people = array("Baker","Cooper","Fletcher","Miller","Smith");
        do {
            shuffle($people);
        } while (!testThisOne($people));
        return $people;
    }

?>

【问题讨论】:

  • ..当然。如果不是这样,请告诉我们您尝试了什么
  • 或许可以将其设为社区 wiki 帖子?
  • 一种方法是查找一些排列算法。然后,您可以计算人和公寓的所有不同排列,并简单地测试每个排列,直到满足所有标准。
  • 也许使用不同的语言 - 这看起来像是 Prolog 的工作!
  • 对我来说,这听起来像是数独的变体(因为你需要根据一些规则“填空”)。如果尚未发布的答案,查找数独求解器可能会给您一个启动。

标签: php logic


【解决方案1】:

有趣的问题。由于这是一个编程挑战,我认为最好的方法就是生成所有可能的人员安排,并测试他们是否正确。

既然你只是想要一个起点,我不会写任何实际的代码,我只会概述我解决它的方法:

  1. 由于所有租户都住在不同的楼层,您需要使用“排列”算法来生成他们所有不同的可能安排。也就是说,您从{1, 2, 3, 4, 5} 之类的集合开始,每个元素代表一个人的楼层编号,例如按 Baker、Cooper、Fletcher、Miller、Smith 的顺序。你需要找到所有其他可能的安排。 The algorithm on wikipedia 相当简单,应该很容易实现。
  2. 对于您生成的每个排列,您需要测试是否所有条件都为真。如果任何条件为假,则停止测试并继续下一个排列。如果所有条件都满足,你就完成了。所有条件都相当容易测试,例如:

    “贝克不住在顶层。” >>$baker != 5

    “米勒住在比库珀更高的楼层。” >>$miller &gt; $cooper

    等等。

【讨论】:

  • 谢谢,这完全有道理,并且大致符合我的解决方案(我即将发布)。
  • "每个元素代表一个人的楼层号" 除了集合中的位置代表楼层号,每个数字(只有5个)代表个人。如果您从这个 POV 开始查看问题,生成排列就变成了以 5 为底数计数到 54321 的问题(实际上您可以根据问题本身应用进一步的优化)。无论如何,我也+1!如果你能改进你的答案会很棒。
【解决方案2】:

我猜你可以将其格式化为一组线性(in)方程。

B < 5
C > 1
F < 5
F > 1
M > C
|S - F| > 1
|F - C| > 1

这些加:B != C != F != S != M

现在将其输入simplex algorithm,您就完成了:)

编辑:但是如果你想以编程方式解决这个问题,我想测试这些条件的所有排列会简单得多——只有 5 个!其中。

【讨论】:

  • 只有5层,不应该是C &gt; 1F &gt; 1吗?
  • 对,我搞砸了索引:)
【解决方案3】:

所以我们称这些人为 B C F M S。

基本上每个人都可以住在任何地方,所以我们有这样的起始情况:

[BCFMS] [BCFMS] [BCFMS] [BCFMS] [BCFMS]

现在你说

贝克不住在顶层。

所以我们会有

[BCFMS] [BCFMS] [BCFMS] [BCFMS] [CFMS]

库珀不住在底层。

所以我们最终得到:

[BFMS] [BCFMS] [BCFMS] [BCFMS] [CFMS]

弗莱彻既不住在顶层也不住在底层。

好的:

[BMS] [BCFMS] [BCFMS] [BCFMS] [CMS]

米勒住在比库珀更高的楼层。

好的,所以M不能低于C:

[BS] [BCFS] [BCFMS] [BCFMS] [CMS]

而且,C 不能在最后一层,因为 M 必须在他的上方:

[BS] [BCFS] [BCFMS] [BCFMS] [MS]

(A):史密斯不住在弗莱彻家附近的楼层。

(B):弗莱彻不住在库珀附近的楼层。

所以相邻的“盒子”(楼层)上没有 S-F、F-S、F-C 或 C-F。

我们也知道

(C):住在公寓的不同楼层

符合(C),我们有两种可能的情况,一楼是B的或者S的

让我们来看第二种情况(因为我们知道(A)关于他)

[S] [BCFS] [BCFMS] [BCFMS] [MS]

根据(A):

[S] [BC] [BCF] [BCF] [M]

所以我们也知道 M 位于 C 之上(前面的步骤已经成立,因为我们知道 M 现在肯定在最后一层):

[S] [BC] [BCF] [BCF] [M]

根据(B),F和C都不能在3楼,在(C)的影响下,由于进一步减少,我们最终得到唯一一种可能的排列(每层只有一个人):

[S] [C] [B] [F] [M]

所以这里是解决方案:

史密斯、库珀、贝克、弗莱彻、米勒

【讨论】:

  • 太棒了,这是一个可读性极强的细分。在阅读这篇文章之前,我已经想出了我的“第一轮”解决方案,但现在我有一个改进的想法。谢谢!
  • 不客气,很高兴我能提供帮助,尽管我的回答纯粹是数学性的,而不是程序性的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-14
  • 1970-01-01
  • 1970-01-01
  • 2011-10-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多