【问题标题】:PHP algorithm which calculates all possible combinations of dividing one set between another setPHP算法,它计算将一组划分到另一组的所有可能组合
【发布时间】:2012-03-16 21:25:08
【问题描述】:

我正在寻找一种二维组合算法..如果这是正确的措辞。我对 PHP 非常有经验,但对算法和高级数学不熟悉,所以请多多包涵。

我有一组元素,我想将它们与另一组元素组合并计算所有可能的组合,以便之后进行分析。集合中元素的数量永远不会改变,两个集合总是有五个元素:

$set1= array('A', 'B', 'C', 'D', 'E');
$set2= array('One', 'Two', 'Three', 'Four', 'Five');

不知道这是否是正确的措辞,但我想查看第 1 组项目的所有组合,在第 2 组项目之间划分。两个集合中的所有元素只能在每种可能性中使用一次,并且 Set 1 元素可以在 Set 2 元素中组合在一起,这样我就得到了一个看起来像这样的结果数组(一些随机值作为示例):

$possibilities= array(
  0 => array(
    'One' => array('A'),
    'Two' => array('B'),
    'Three' => array('C'),
    'Four' => array('D'),
    'Five' => array('E'),
  ),
  1 => array(
    'One' => array('A', 'B', 'C'),
    'Two' => array('D'),
    'Three' => array('E'),
    'Four' => array(),
    'Five' => array(),
  ),
  2 => array(
    'One' => array('C'),
    'Two' => array(),
    'Three' => array('A'),
    'Four' => array('B'),
    'Five' => array('D', 'E'),
  ),
  3 => array(
    'One' => array(),
    'Two' => array(),
    'Three' => array('A', 'B', 'C', 'D', 'E'),
    'Four' => array(),
    'Five' => array(),
  ),
);

等等……那些价值观。欢迎对此提出任何反馈,尤其是:

  • 如何在 PHP 中编写类似的代码?通过递归函数?我是否使用笛卡尔积算法?
  • 可能有多少种组合? 5^10 ?
  • 根据前一点:在 Web 应用程序中实时处理这些数据是否可行?如果我有 1000 万个组合,我可能需要提前进行计算,保存结果分析并在实时应用执行期间使用它?
  • 有一些限制(例如:设置 2 项“一”、“二”和“三”应始终至少包含一组 1 中的一项)但无用的组合将在之后的分析过程中被删除,因此无需包括该组合在组合算法中,除非它可以通过在那时构建这些来减少计算时间?

我的问题可能不是很清楚,所以请问我是否需要提供更多或更好的信息。

提前致谢


2012 年 2 月 28 日更新

我已经尝试了我在互联网上找到的 Power Set 和笛卡尔积函数的 PHP 实现(这种东西有点超出我自己尝试和编码的能力)。所以当我执行这段代码时:

$powerset= powerSet(array('A', 'B', 'C'));
$cartesian = cartesian(array(
    'Set1' => $powerset,
    'Set2' => array('One', 'Two', 'Three')
));

这是 powerSet 函数放入 $powerset 的内容:

Array (
      [0] => Array ()
      [1] => Array (
        [0] => A
      )
      [2] => Array (
        [0] => B
      )
      [3] => Array (
        [0] => B
        [1] => A
      )
      ...

这就是笛卡尔函数返回的结果:

Array (
      [0] => Array (
        [Set1] => Array ()
        [Set2] => One
      )
      [1] => Array (
        [Set1] => Array (
          [0] => A
        )
        [Set2] => One
      )
      [2] => Array (
        [Set1] => Array (
          [0] => B
        )
        [Set2] => One
      )
      [3] => Array (
        [Set1] => Array (
          [0] => B
          [1] => A
        )
        [Set2] => One
      )
      ...

所以它有点像我想要的,但不是最难的部分。它“单独”考虑组合,并且不在 Set2 中分配 Set1,确保所有三个 Set2 项目都使用所有 Set1 项目。


另一个更新:在没有编程参考的情况下重述问题

这个问题与我为战略游戏创建的分析工具有关。每次使用该工具时,玩家可以从大量单位中选择 5 个不同的单位。这些单元可以以多种方式与其他(静态)实体(我们称这些“池”)组合。如果将这些单位与某些池相结合,这些单位具有可能会或可能不会改善玩家策略的特征。例如:

  • A 单元喜欢在 1 号池,但不喜欢在 2 号池
  • 单元 B 讨厌在池 1 中,除非单元 A 也在那里
  • 等等..

该工具的目的是找出哪些单位进入哪个池的最佳组合。这些是规则:

  • 总是从大约 50 个集合中选出 5 个不同的单元。所有这些单元都有不同的特征。
  • 总是有相同的 5 个池。它们具有不同的特征,但池不是从更大的集合中选择的,它们始终相同。
  • 每个池可以包含多个单元,从 0 到 5。
  • 每个单元只能在一个池中。

输入是:

  • 5 个变量单位的列表:A、B、C、D、E
  • 5 个静态池的列表:Pool1、Pool2、Pool3、Pool4、Pool5

输出应该是这两个列表之间所有可能的组合,基于上述规则。一些例子:

组合1

  • 池 1:A
  • 池 2:B
  • 池 3:C
  • 池 4:D
  • 池 5:E

组合2

  • 池 1:A、B、C
  • 池 2:D
  • 池 3:E
  • 池 4:
  • 池 5:

组合3

  • 池 1:C
  • 池 2:
  • 池 3:A
  • 池 4:B
  • 5 号组:D、E

组合4

  • 池 1:
  • 池 2:
  • 池 3:A、B、C、D、E
  • 池 4:
  • 5 号池:

等等……

所以我想做的事情是:

  1. 采用存在的所有可能的单元和池组合。
  2. 遍历它们并根据单元和池之间的协同作用为组合分配“战略价值”。
  3. 选取“策略价值”最高的前 10 个组合

第 2 步和第 3 步没问题。 我遇到的问题是生成池中所有可能的单元组合。

希望这是对问题的更清晰的描述

【问题讨论】:

  • “设置 2 项“一”、“二”和“三”应始终至少包含一组 1 中的一项”,那么这不应该反映在您的示例中吗?
  • 这让我想起了几年前读到的一个组合数学问题。我感觉有 5 个元素的解决方案,但没有已知的解决方案 6... 或类似的东西。您可能需要扩展您想要实现的确切目标。也许你根本不需要编写获奖算法:)
  • 在分割数组中排序是否重要?例如对于这个问题,array('A','B','C') 是否认为与 array('B','C','A') 相同?
  • @Ward Muylaert:如前所述,这不是必需的。分析过程中会丢弃无用的结果。
  • @Pete:是一款策略游戏的分析工具。单元(第 1 组)及其位置(第 2 组)的组合将根据与这些位置相关的单元特征产生不同的值(在分析期间)。可能性的数量有点压倒性,所以我想采取所有可能性,分析集合,分配一个值,然后选择前 3 个可能性。

标签: php algorithm combinations cartesian-product divide


【解决方案1】:

好的,所以现在我想我已经知道你想做什么了。单位集合不是单位集的幂集的元素,它们是(几乎)单位集的partitions 的元素。我写“几乎”是因为,严格来说,空集不是集合的分区集合的成员。现在我认为你的问题是计算一组 5 个单元的所有分区;该分区最多有 5 个元素(每个元素包含一个单元)。对于您的问题,本身不包含 5 个成员的单元集的任何分区都应填充出现的空集。

现在您必须将这些分区映射到池的顺序。您的第一个组合将池映射到单元集分区的元素,因此:{1->{A}, 2->{B}, 3->{C}, 4->{D}, 5->{E}}。如果您还想要将池映射到单元集的同一分区的其他组合(例如{2->{A}, 3->{B}, 4->{C}, 5->{D}, 1->{E}},那么您必须计算池的所有permutations,并将每个池映射到集合的同一分区单位。

重复直到完成。

【讨论】:

  • 所以它是通过笛卡尔积。这需要一些学习,但我会尝试一下。谢谢!
  • 我试图实现一个幂集和笛卡尔积 PHP 函数来完成我想要的,但我认为我的方法是完全错误的。你愿意再看看吗?
  • 问题不在于编码能力。我不懂数学方法,我是一名没有受过正规教育的网络开发人员。电源组并不是真正的问题,更多的是笛卡尔积,我无法编写我无法理解的代码。我可以看到这些计算如何接近解决我的问题,但现在他们如何实际解决它。不过谢谢回复,我会想办法的。
  • 不要害怕“笛卡尔积”是一个困难的数学概念。对于集合 {a,b,c} 和 {1,2,3 } 它只是集合 {(a,1),(a,2),(a,3),(b,1),(b,2 ),(b,3),(c,1),(c,2),(c,3)} - 真的没有比这更复杂的了。
  • 但这不是我想要的。我可以理解。我也可以理解电源设置功能。问题是:我无法编写将这两者结合起来的函数,因为我看不出它们如何解决问题。所以我拿了两个现有的功能,只是试着把它们砸在一起。我单独理解它们,我只是看不出它们(如你所建议的那样)如何结合起来解决我的问题。在这里尽量说清楚:阻碍我的不是编码,也不是对这两个函数的理解,而是看看如何以一种得到我想要的结果的方式组合这些计算。
【解决方案2】:

您可以使用 kd-tree 或 treemap 算法。这种算法很好地找到最近的邻居,最近的点对或寻址空间,平铺空间。

【讨论】:

  • 我对 HighPerformanceMark 感到有些怀疑,但我会调查一下。感谢您的建议!
猜你喜欢
  • 2020-06-19
  • 1970-01-01
  • 2015-11-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多