Php 具有特定准则的笛卡尔积
我试图找到笛卡尔积并附加特定的条件 我有四个游泳池,每人25人。每个人都有分数和价格。每个池中的每个人看起来都是这样的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 ) 我想找到最好的人的
[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) {