一种受限的笛卡尔积计算-PHP
编辑1-自从发布后,我了解到基本问题是如何找到笛卡尔产品(现在去谷歌),但这不仅仅是因为我不想每次烫发,我想找到使用相同子数组键的笛卡尔积,每次置换不超过一次,我的“额外”问题更多的是关于如何最小化笛卡尔积所需的工作量(我必须说,接受较小的错误率)- 想象一下。。。我有四个厨师和四个食谱,每个厨师对每个食谱都有一个分数,今天我希望每个厨师做一道菜(但没有一道菜应该做两次),决定应该基于所有四道菜的最佳(最高总分)排列(所以可能一个厨师不会做出他个人最好的) 我已经将数据放入多维数组中一种受限的笛卡尔积计算-PHP,php,arrays,combinations,cartesian-product,Php,Arrays,Combinations,Cartesian Product,编辑1-自从发布后,我了解到基本问题是如何找到笛卡尔产品(现在去谷歌),但这不仅仅是因为我不想每次烫发,我想找到使用相同子数组键的笛卡尔积,每次置换不超过一次,我的“额外”问题更多的是关于如何最小化笛卡尔积所需的工作量(我必须说,接受较小的错误率)- 想象一下。。。我有四个厨师和四个食谱,每个厨师对每个食谱都有一个分数,今天我希望每个厨师做一道菜(但没有一道菜应该做两次),决定应该基于所有四道菜的最佳(最高总分)排列(所以可能一个厨师不会做出他个人最好的) 我已经将数据放入多维数组中 arra
array(
array (1,2,3,4),
array (35,0,0,0),
array (36,33,1,1),
array (20,20,5,3)
)
- 它在每个子数组中的值对数与子数组数相同(如果有帮助的话)
- 实际上,子阵列的数量最多将达到8个(因此,最大perms=8!,大约40000个,而不是8^8个,因为不允许多种组合)
- 如果有帮助的话,选择这种格式的数据是灵活的
$mainArr = array(
array (1,2,3,4) ,
array (35,0,0,0) ,
array (36,33,1,1) ,
array (20,20,5,3)
);
$i = 0;
foreach( $mainArr as $subArray )
{
foreach( $subArray as $key => $value)
{
$newArr[$key][$i]=$value;
$i++;
}
}
$finalArr = array();
foreach( $newArr as $newSubArray )
{
$finalArr[] = max($newSubArray);
}
print_r( $finalArr );
我可以用这个算法为你提供一个起点,该算法尝试根据最大分数与分数之和的比率来选择厨师(因此,尝试选择一个菜谱非常好,但其他菜谱不好的厨师来做这个菜谱) 对于提供的数据集,它确实找到了最佳答案(35,33,5,4)。但是,它仍然不是完美的,例如,对于阵列:
$cooks = array(
array(1,2,3,4),
array(35,0,33,0),
array(36,33,1,1),
array(20,20,5,3)
);
理想的答案是(20,33,33,4),但是该算法将返回(35,33,5,4)
但既然问题是问从哪里开始,我想这至少可以作为一个开始:p抱歉,但这将是一个逻辑布局,而不是代码 我不太清楚数组(1,2,3,4)是第一道菜的分数还是第一个厨师的分数,但我可能会使用这样的数组:
$array[$cook_id][$dish_number] = $score;
asort()每个数组,以便$array[$cook\u id]=数组($lower\u scored\u dish,…$highest)
考虑到某个厨师制作一道菜的加权偏好是最好的菜和另一道菜的得分之差
作为一个非常简单的例子,烹饪a、b、c和菜肴0、1、2
$array['a'] = array(0=>100, 1=>50, 2=>0); // cook a prefers 0 over 1 with weight 50, over 2 with weight 100
$array['b'] = array(0=>100, 1=>100, 2=>50); // cook b prefers 0,1 over 2 with weight 50
$array['c'] = array(0=>50, 1=>50, 2=>100); // cook c prefers 2 with weight 50
在asort()之后:
$array['a']=array(0=>100,1=>50,2=>0);
$array['b']=array(0=>100,1=>100,2=>50);
$array['c']=array(2=>100,0=>50,1=>50)
从厨师“a”开始,他喜欢第0道菜,而不是他下一道最好的菜50分(体重)。厨师“b”也更喜欢dih 0,但与下一道菜相比重量为0。因此,厨师“a”很可能(尽管目前还不能确定)将菜肴制作成0
考虑保留菜0并继续烹饪“b”。除了菜0,厨师“b”更喜欢菜1。没有其他厨师更喜欢菜1,因此厨师“b”被指定为菜1
厨师“c”默认获得第2道菜
这是一个非常方便的例子,每个厨师都可以做一些属于个人最大值的东西,但我希望它能说明一些可以解决的逻辑
让我们让它变得不那么方便:
$array['a'] = array(0=>75, 1=>50, 2=>0);
$array['b'] = array(0=>100, 1=>50, 2=>50);
$array['c'] = array(0=>100, 1=>25, 2=>25);
$array['a'] = array(0=>200, 1=>148, 2=>148, 3=>0);
$array['b'] = array(0=>200, 1=>149, 2=>0, 3=>0);
$array['c'] = array(0=>200, 1=>150, 2=>147, 3=>147);
$array['d'] = array(0=>69, 1=>18, 2=>16, 3=>15);
再次从厨师“a”开始,看看0是首选,但这次是25。厨师“b”首选50,厨师“c”首选75。厨师“c”赢得0
回到可用厨师列表,“a”更喜欢重量为50的1号,但“b”更喜欢重量为0的1号。“a”得到第1道菜,“b”得到第2道菜
这仍然没有考虑到所有的复杂性,但这是朝着正确方向迈出的一步。有时,第一次烹饪/菜肴组合的假设是错误的
不太方便的方式:
$array['a'] = array(0=>75, 1=>50, 2=>0);
$array['b'] = array(0=>100, 1=>50, 2=>50);
$array['c'] = array(0=>100, 1=>25, 2=>25);
$array['a'] = array(0=>200, 1=>148, 2=>148, 3=>0);
$array['b'] = array(0=>200, 1=>149, 2=>0, 3=>0);
$array['c'] = array(0=>200, 1=>150, 2=>147, 3=>147);
$array['d'] = array(0=>69, 1=>18, 2=>16, 3=>15);
“a”得到0,因为这是最大值,其他喜欢0的人没有更高的权重
“b”以149的权重赢得1分
“d”赢2,因为“c”没有可用选项的首选项
c得3分
分数:200+149+147+16=512
虽然这是一个很好的猜测,但是没有检查每个排列,它可能是错误的。从这里开始,问:“如果一个厨师与其他厨师交易,那么总数会增加吗?”
答案是肯定的,a(0)+d(2)=200+16=216,但a(2)+d(0)=148+69=217
我将让您使用加权方法编写“最佳猜测”的代码,但在此之后,您有一个良好的开端:
// a totally uneducated guess...
$picks = array(0=>'a', 1=>'b', 2=>'c', 3=>'d');
do {
$best_change = false;
$best_change_weight = 0;
foreach ($picks as $dish1 => $cook1) {
foreach ($picks as $dish2 => $cook2) {
if (($array[$cook1][$dish1] + $array[$cook2][$dish2]) <
($array[$cook1][$dish2] + $array[$cook2][$dish1]))
{
$old_score = $array[$cook1][$dish1] + $array[$cook2][$dish2];
$new_score = $array[$cook1][$dish2] + $array[$cook2][$dish1];
if (($new_score - $old_score) > $best_change_weight) {
$best_change_weight = $new_score - $old_score;
$best_change = $dish2;
}
}
}
if ($best_change !== false) {
$cook2 = $picks[$best_change];
$picks[$dish1] = $cook2;
$picks[$dish2] = $cook1;
break;
}
}
} while ($best_change !== false);
如果a1+b2==a2+b1,那么“a”和“b”将不会切换盘子。我不能100%确定的情况是,是否存在这样一个矩阵,这是一个更好的选择:
a1 [a2] a3
b1 b2 [b3]
[c1] c2 c3
从第一个状态到第二个状态需要两个开关,第一个开关似乎是任意的,因为它不会改变总的状态。但是,只有通过这个任意的变化,才能做出最后一个开关
我试图找到一个3x3的例子,这样基于我上面提到的“加权偏好”模型,第一个会被选择,但也会是真正的最优
<?php
function pc_next_permutation($p, $size) {
//this is from http://docstore.mik.ua/orelly/webprog/pcook/ch04_26.htm
// slide down the array looking for where we're smaller than the next guy
for ($i = $size - 1; $p[$i] >= $p[$i+1]; --$i) { }
// if this doesn't occur, we've finished our permutations
// the array is reversed: (1, 2, 3, 4) => (4, 3, 2, 1)
if ($i == -1) { return false; }
// slide down the array looking for a bigger number than what we found before
for ($j = $size; $p[$j] <= $p[$i]; --$j) { }
// swap them
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
// now reverse the elements in between by swapping the ends
for (++$i, $j = $size; $i < $j; ++$i, --$j) {
$tmp = $p[$i]; $p[$i] = $p[$j]; $p[$j] = $tmp;
}
return $p;
}
$cooks[441] = array(340=>5,342=>43,343=>50,344=>9,345=>0);
$cooks[442] = array(340=>5,342=>-33,343=>-30,344=>29,345=>0);
$cooks[443] = array(340=>5,342=>3,343=>0,344=>9,345=>10,);
$cooks[444] = array(340=>25,342=>23,343=>20,344=>19,345=>20,);
$cooks[445] = array(340=>27,342=>27,343=>26,344=>39,345=>50,);
//a consideration: this solution requires that the number of cooks equal the number of recipes
foreach ($cooks as $cooksCode => $cooksProfile){
$arrayOfCooks[]=$cooksCode;
$arrayOfRecipes = (array_keys($cooksProfile));
}
echo "<br/> here is the array of the different cooks<br/>";
print_r($arrayOfCooks);
echo "<br/> here is the array of the different recipes<br/>";
print_r($arrayOfRecipes);
$set = $arrayOfCooks;
$size = count($set) - 1;
$perm = range(0, $size);
$j = 0;
do {
foreach ($perm as $i) { $perms[$j][] = $set[$i]; }
} while ($perm = pc_next_permutation($perm, $size) and ++$j);
echo "<br/> here are all the permutations of the cooks<br/>";
print_r($perms);
$bestCombo = 0;
foreach($perms as $perm){
$thisScore =0;
foreach($perm as $key =>$cook){
$recipe= $arrayOfRecipes[$key];
$cookScore =$cooks[$cook][$recipe];
$thisScore = $thisScore+$cookScore;
}
if ($thisScore>$bestCombo){
$bestCombo=$thisScore;
$bestArray= $perm;
}
}
echo "<br/> here is the very best array<br/>";
print_r ($bestArray);
echo "<br/> best recipe assignment value is:".$bestCombo."<br/><br/>";
?>