2

私は次のような配列を持っています

$array = array(3,5,6,10,15,30);
$sum = 69;

次に、69に等しい3つの異なる合計があります。

3+5+6+10+15+30,
3+6+10+20+30,
3+6+30+30,

最高のものは3+6 + 30+30です。配列からのより高い数が含まれているため、数を減らす合計を完了します。

(数値は、リストに表示されている回数だけ合計内で使用でき、単一の数値は合計としてカウントされます。)これが私が実装しているコードです。

$sum = 18;
$list = array();
$this->sumUpRecursive(array(3,5,6,10,15,30), $list);  //function call
$list = array_filter($list,function($var) use ($sum) { return(array_sum($var) == $sum);});
var_dump($list);

function sumUpRecursive($array, &$list, $temp = array()) {
      if (count($temp) > 0 && !in_array($temp, $list))
        $list[] = $temp;
      for ($i = 0; $i < sizeof($array); $i++) {
        $copy = $array;
        $elem = array_splice($copy, $i, 1);
        if (sizeof($copy) > 0) {
          $add = array_merge($temp, array($elem[0]));
          sort($add);
          $this->sumUpRecursive($copy, $list, $add);
        }
        else {
          $add = array_merge($temp, array($elem[0]));
          sort($add);
          if (!in_array($temp, $list)) {
            $list[] = $add;
          }
        }
      }
    }

結果:

Array
    (
[9] => Array
    (
        [0] => 3
        [1] => 5
        [2] => 10
    )

[28] => Array
    (
        [0] => 3
        [1] => 15
    )

)。

これは少し複雑かもしれません。配列から数値を1回取得します。しかし、69を理解する方法...

ありがとう

4

1 に答える 1

1

これはあなたのために働くはずです:

このコードは何をしますか (関数getKnapsackSum())?

1.データを準備する

関数の最初の数行でデータを準備します。つまり、配列 DESC を でソートしrsort()ます。でリストの最後の要素を取得しend()、配列ポインタをリセットrest()して一時変数に割り当てます。

2.入力チェック

合計の計算を開始する前に、入力が 0 でないことを確認します。

3.合計を計算する

この後、本当のことが起こります (IT ブードゥー教、そうではありません)! 合計が得られない限り、false であるループから始めます。while ループの次の 2 行は、最初に合計を計算できない場合は 0 を含む配列を返すことを確認し、次に、配列ポインターの「オフセット」を取得したときに設定したことを確認します。最後の配列要素に戻ります。

次に、最初の if 句があり、間違いがあったかどうかを確認し、より低い値で試行する必要があります。例として:

list = [3, 5, 6]
sum = 8

                        //entire sum
                        | 0
                        |
check 6:                |
                        |
      6 + sum  -> 8     | 6               | fits
      6 + sum  -> 8     |                 | does not fit
                        |
check 5:                |
                        |
      5 + sum  -> 8     |                 | does not fit
                        |
check 3:                |
                        |
      3 + sum  -> 8     |                 | does not fit

--------------------------------------------------------
                          = sum = [6] != 8

この例でわかるように、アルゴリズムは 6 で合計を作成し始めたため、間違いを犯しましたが、その後は最後まで作成できませんでした。配列ポインターの現在の要素は配列の末尾であり、この値 + 現在の合計は目標よりも高くなります。

この場合、合計配列から最後の値を削除し、リストの最上位の要素を取り出します。そのため、次のデータを使用して再試行します。

list = [3, 5]
          //^ As you can see it removed the highest value of the list 
sum = 8

                        //entire sum
                        | 0 <- it removed the last value of the sum array, here 6
                        |
check 5:                |
                        |
      5 + sum  -> 8     | 5               | fits
      5 + sum  -> 8     |                 | does not fit
                        |
check 3:                |
                        |
      3 + sum  -> 8     | 3               | fits
      3 + sum  -> 8     |                 | does not fit

--------------------------------------------------------
                          = sum = [5, 3] == 8

ご覧のとおり、最初の if 句により、リストを使用して合計を作成できました。そのため、if ステートメントは、レベル 1 のエラーを確実に修正します。

while ループの 2 番目の if ステートメントは、レベル 2 のエラーを修正します。では、レベル 2 のエラーとは何でしょうか? また、例をもう一度見てみましょう。

list = [3, 5, 6]
sum = 22

                        //entire sum
                        | 0
                        |
check 6:                |
                        |
      6 + sum  -> 22    | 6               | fits
      6 + sum  -> 22    | 6               | fits
      6 + sum  -> 22    | 6               | fits
      6 + sum  -> 22    |                 | does not fit
                        |
check 5:                |
                        |
      5 + sum  -> 22    |                 | does not fit
                        |
check 3:                |
                        |
      3 + sum  -> 22    | 3               | fits
      3 + sum  -> 22    |                 | does not fit

--------------------------------------------------------
                          = sum = [6, 6, 6, 3] != 22

ご覧のとおり、合計を完全に構築することはできませんでした。ただし、今回はレベル 1 のエラーではありません。現在の合計から最後の要素を削除し、最上位の要素を削除した新しいリストを調べても、ここでわかるようにまだ合計を作成できないためです。 :

エラーの修正レベル 1:

list = [3, 5]
          //^ As you can see it removed the highest value of the list 
sum = 22

                        //entire sum
                        | [6, 6, 6] <- it removed the last value of the sum array, here 3
                        |
check 5:                |
                        |
      5 + sum  -> 22    |                | does not fit
                        |
check 3:                |
                        |
      3 + sum  -> 22    | 3              | fits
      3 + sum  -> 22    |                | does not fit
                        |
--------------------------------------------------------
                          = sum = [6, 6, 6, 3] != 22

ご覧のとおり、スタックしていることがわかりますが、最初の if 句だけでは間違いを修正できません。そして、ここで 2 番目の if ステートメントがリストが空かどうかをチェックします。この場合は、すべての値を試したことを意味しますが、間違いは sum 配列の上位にあります。

したがって、合計配列の配列要素を 1 つ戻して削除します。また、間違いであった番号のないリストを取得するために、間違いをオフセットとして取得します。ここで[6, 6, 6, 3]は、最初の if 句から 3 が削除されるため、配列は次のようになります[6, 6, 6]。2 番目の if ステートメントは、間違いが 6 だったことを確認します。それを削除し、数字を選択するリストを修正します。

結果の配列は次のよう[6, 6]になり、数値を選択するリストは次のようになります[5, 3]。そして、レベル 2 の修正を行ったので、以下に示すように合計を作成できます。

list = [3, 5]
          //^ As you can see it removed the highest value of the list 
sum = 22

                        //entire sum
                        | [6, 6] <- it removed the last value of the sum array, here 3 and 6
                        |
check 5:                |
                        |
      5 + sum  -> 22    | 5              | fits
      5 + sum  -> 22    | 5              | fits
      5 + sum  -> 22    |                | does not fit
                        |
check 3:                |
                        |
      3 + sum  -> 22    |                | does not fit
                        |
                        |
--------------------------------------------------------
                          = sum = [6, 6, 5, 5] == 22

したがって、この後、リストの現在の値が合計配列に収まり、目標よりも大きくないかどうかを確認するためだけに if else ステートメントがあります。収まる場合は配列に追加し、そうでない場合は次のリスト要素に移動します。


ご覧のとおり、私のコードはいくつかのエラーを修正していますが、それがすべてで機能することを 100% 確信しているわけではなく、sum 配列に戻る必要があるレベル 3 のエラーを生成できるかどうかもわかりません正しい 3 つの値があり、1 つある場合、コードがそれを修正するかどうか、または無限ループに陥るかどうかもわかりません。

しかし、ここで話していることはすべて、すべての魔法を行うコードです。

<?php

    //data
    $arr = [3,5,6,10,15,30];
    $sum = 69;


    //get sum
    function getKnapsackSum($arr, $sum) {
        //prepare data
        rsort($arr);
        $end = end($arr);
        reset($arr);
        $tmp = $arr;
        $result = [];

        //check if it is not a empty input
        if($sum == 0 || empty($tmp) || array_sum($tmp) == 0) return [0];

        //calculate the sum
        while(array_sum($result) != $sum) {
            if(empty($tmp) && empty($result)) return [0];
            if(current($tmp) === FALSE) end($tmp);

            //correction for errors level 1
            if(current($tmp) == $end && array_sum($result) + current($tmp) > $sum) {
                array_pop($result);
                array_shift($tmp);
                reset($tmp);
            }

            //correction for errors level 2
            if(empty($tmp)) {
                $mistake = array_pop($result);
                if($mistake == NULL) return [0];
                $tmp = array_slice($arr, array_search($mistake, $arr)+1);
                reset($tmp);
            }

            if(array_sum($result) + current($tmp) <= $sum)
                $result[] = current($tmp);
            else
                next($tmp);     
        }
        return $result;
    }


    $result = getKnapsackSum($arr, $sum);
    print_r($result);

?>

出力:

Array ( [0] => 30 [1] => 30 [2] => 6 [3] => 3 )

また、入力のいくつかの例と、コードからの出力があります。

    input        |        output    
------------------------------------
 list: []        |
 goal:  0        |  sum: [0]
------------------------------------
 list: []        |
 goal:  1        |  sum: [0]
------------------------------------
 list: [0]       |
 goal:  1        |  sum: [0]
------------------------------------
 list: [0]       |
 goal:  0        |  sum: [0]
------------------------------------
 list: [3, 5, 6] |  //error level 1
 goal:  8        |  sum: [5, 3]
------------------------------------
 list: [3, 5, 6] |  //error level 2
 goal: 22        |  sum: [6, 6, 5, 5]
------------------------------------
 list: [5, 7, 9] |  //can't build the sum
 goal: 56        |  sum: [0]
------------------------------------
 list: [5, 7, 9] |
 goal: 34        |  sum: [9, 9, 9, 7]
------------------------------------
于 2015-03-05T05:17:55.770 に答える