Php 具有特定准则的笛卡尔积

Php 具有特定准则的笛卡尔积,php,arrays,algorithm,permutation,cartesian-product,Php,Arrays,Algorithm,Permutation,Cartesian Product,我试图找到笛卡尔积并附加特定的条件 我有四个游泳池,每人25人。每个人都有分数和价格。每个池中的每个人看起来都是这样的 [0] => array( "name" => "jacob", "price" => 15, "score" => 100 ), [1] => array( "name" => "daniel", "price" => 22, "score" => 200 ) 我想找到最好的人的

我试图找到笛卡尔积并附加特定的条件

我有四个游泳池,每人25人。每个人都有分数和价格。每个池中的每个人看起来都是这样的

[0] => array(
    "name" => "jacob",
    "price" => 15,
    "score" => 100
),
[1] => array(
    "name" => "daniel",
    "price" => 22,
    "score" => 200
)
我想找到最好的人的组合,从每个池中挑选一个人。但是,有一个最高价格,任何分组都不能超过某个价格

我一直在搞笛卡尔函数和置换函数,似乎不知道怎么做。我知道如何对其进行编码的唯一方法是使用嵌套的
foreach
循环,但这非常费劲

正如您所看到的,下面的代码效率极低。尤其是如果游泳池增加

foreach($poolA as $vA) {
   foreach($poolb as $vB) {
       foreach($poolC as $vC) {
            foreach($poolD as $vD) {

                // calculate total price and check if valid
                // calculate total score and check if greatest
                // if so, add to $greatest array

            }
        }
    }    
}      

我还认为我可以找到一种方法来计算总价格/得分比率,并利用它来发挥我的优势,但我不知道我遗漏了什么。

关于您的方法,这里有几点需要注意。严格地说,从数学的角度来看,你们计算的排列比得到一个明确答案所需的排列要多得多

在组合数学中,有两个重要的问题要问,以获得产生所有可能组合所需的确切排列数

  • 秩序重要吗?(就您的情况而言,它不是)
  • 允许重复吗?(对于您的情况,无需重复)
  • 因为这两个问题的答案都是否定的,所以您只需要当前使用嵌套循环进行迭代的一小部分。目前您正在执行,
    pow(25,4)
    permutations,即
    390625
    。您实际上只需要
    n!/R(右)
    gmp\u事实(25)/(gmp\u事实(4)*gmp\u事实(25-4))
    仅为
    12650
    所需的总排列

    下面是一个简单的函数示例,该函数使用PHP中的生成器(取自)生成无重复的组合(顺序无关紧要)

    修改生成器函数以检查价格总和是否满足/超过所需阈值并仅从中返回有效结果(即在需要时提前放弃)将非常容易

    这里重复和顺序对于您的用例并不重要的原因是,无论您添加
    $price1+$price2
    还是
    $price2+$price1
    ,结果都毫无疑问是相同的。因此,您只需将每个唯一集合相加一次,即可确定所有可能的总数。

    正如所指出的,对每个集合中的人员进行排序,可以在总价格超过限制时提前停止循环,从而减少需要检查的案例数。然而,应用这种改进的渐进复杂性仍然是O(n4)(其中
    n
    是池中的人数)

    我将概述一种具有更好渐进复杂性的替代方法,如下所示:

  • 构建一个包含所有成对人员的池
    X
    ,其中一人来自池
    a
    ,另一人来自池
    B
  • 构建一个包含所有成对人员的池
    Y
    ,其中一人来自池
    C
    ,另一人来自池
    D
  • 按总价对池
    X
    中的对进行排序。然后,对于价格相同的任何一对,保留得分最高的一对,并丢弃其余的一对
  • 按总价对池
    Y
    中的对进行排序。然后,对于价格相同的任何一对,保留得分最高的一对,并丢弃其余的一对
  • 使用两个指针进行循环,检查满足价格约束的所有可能组合,其中
    指针从池
    X
    中的第一个项目开始,而
    指针从池
    Y
    中的最后一个项目开始。下面给出了示例代码,以说明此循环的工作原理:
  • ==========================================================================

    $head = 0;
    $tail = sizeof($poolY) - 1;
    
    while ($head < sizeof($poolX) && $tail >= 0) {
        $total_price = $poolX[$head].price + $poolY[$tail].price;
    
        // Your logic goes here...
    
        if ($total_price > $price_limit) {
            $tail--;
        } else if ($total_price < $price_limit) {
            $head++;
        } else {
            $head++;
            $tail--;
        }
    }
    
    for ($i = $head; $i < sizeof($poolX); $i++) {
        // Your logic goes here...
    }
    
    for ($i = $tail; $i >= 0; $i--) {
        // Your logic goes here...
    }
    
    $head=0;
    $tail=sizeof($poolY)-1;
    而($head=0){
    $total_price=$poolX[$head]。price+$poolY[$tail]。price;
    //你的逻辑是这样的。。。
    如果($total_price>$price_limit){
    $tail--;
    }其他如果($total_price<$price_limit){
    $head++;
    }否则{
    $head++;
    $tail--;
    }
    }
    对于($i=$head;$i=0;$i--){
    //你的逻辑是这样的。。。
    }
    
    ==========================================================================

    $head = 0;
    $tail = sizeof($poolY) - 1;
    
    while ($head < sizeof($poolX) && $tail >= 0) {
        $total_price = $poolX[$head].price + $poolY[$tail].price;
    
        // Your logic goes here...
    
        if ($total_price > $price_limit) {
            $tail--;
        } else if ($total_price < $price_limit) {
            $head++;
        } else {
            $head++;
            $tail--;
        }
    }
    
    for ($i = $head; $i < sizeof($poolX); $i++) {
        // Your logic goes here...
    }
    
    for ($i = $tail; $i >= 0; $i--) {
        // Your logic goes here...
    }
    

    步骤1和2的复杂性是O(n2),步骤3和4的复杂性可以使用平衡二叉树在O(n2 log(n))中完成。步骤5本质上是对n2项的线性扫描,所以复杂度也是O(n2)。因此,该方法的总体复杂性为O(n2 log(n))。

    与Chiwang的解决方案类似,您可以预先消除每个组成员,其中该组中存在另一个组成员,以相同或更高的分数获得更低的价格。 也许你可以用这种方法消除每个小组中的许多成员

    然后,您可以使用此技术,构建两对并重复过滤(消除对,如果存在另一对,则以相同或更低的成本获得更高的分数),然后以相同的方式组合对,或者逐步添加成员(一对、三对、四对)

    如果存在一些会员,他们自己超过了允许的总价,他们可以被提前淘汰


    如果您按分数降序排列4组,并且找到了一个解决方案,其中总价是合法的,那么您就找到了一组给定abc的最佳解决方案

    这里的回复帮助我找到了最好的方法

    我还没有优化函数,但基本上我一次遍历两个结果,以找到t中每个组合的综合工资/分数
    $results = array();
    foreach($poolA as $A) {
        foreach($poolB as $B) {
            $total_salary = $A['Salary'] + $B['Salary'];
            $total_score =  $A['Score'] + $B['Score'];
            $pids = array($A['pid'], $B['pid']);
    
            if(isset($results[$total_salary]) {
                 if($total_score > $results[$total_salary]['Score']) {
                     $results[$total_salary]['Score'] => $total_score;
                     $results[$total_salary]['pid'] => $pids; 
            } else {
                $results[$total_salary]['Score'] = $total_score;
                $results[$total_salary]['pid'] = $pids;
            }
        }         
    }
    
    foreach($results as $R) {
        foreach($poolC as $C) {