10

荷物があるとします。A 地点から B 地点、B 地点から C 地点、そして最後に C 地点から D 地点に移動する必要があります。5 日以内に到達する必要があり、できるだけ少ない金額で済みます。各レグには 3 つの可能な荷送人があり、各レグにはそれぞれ異なる時間とコストがあります。

Array
(
    [leg0] => Array
        (
            [UPS] => Array
                (
                    [days] => 1
                    [cost] => 5000
                )

            [FedEx] => Array
                (
                    [days] => 2
                    [cost] => 3000
                )

            [Conway] => Array
                (
                    [days] => 5
                    [cost] => 1000
                )

        )

    [leg1] => Array
        (
            [UPS] => Array
                (
                    [days] => 1
                    [cost] => 3000
                )

            [FedEx] => Array
                (
                    [days] => 2
                    [cost] => 3000
                )

            [Conway] => Array
                (
                    [days] => 3
                    [cost] => 1000
                )

        )

    [leg2] => Array
        (
            [UPS] => Array
                (
                    [days] => 1
                    [cost] => 4000
                )

            [FedEx] => Array
                (
                    [days] => 1
                    [cost] => 3000
                )

            [Conway] => Array
                (
                    [days] => 2
                    [cost] => 5000
                )

        )

)

プログラムで最適な組み合わせを見つけるにはどうすればよいでしょうか?

これまでの私の最善の試み(3番目または4番目のアルゴリズム)は次のとおりです。

  1. 各区間で最長の荷送人を見つける
  2. 最も「高価な」ものを排除する
  3. 各区間で最も安い荷送人を見つける
  4. 総費用と日数を計算する
  5. 日数が許容できる場合は終了、そうでない場合は 1 に移動

PHP ですばやくモックアップします (以下のテスト配列は問題なく動作しますが、上記のテスト配列で試してみると、正しい組み合わせが見つからないことに注意してください)。

$shippers["leg1"] = array(
    "UPS"    => array("days" => 1, "cost" => 4000),
    "Conway" => array("days" => 3, "cost" => 3200),
    "FedEx"  => array("days" => 8, "cost" => 1000)
);

$shippers["leg2"] = array(
    "UPS"    => array("days" => 1, "cost" => 3500),
    "Conway" => array("days" => 2, "cost" => 2800),
    "FedEx"  => array("days" => 4, "cost" => 900)
);

$shippers["leg3"] = array(
    "UPS"    => array("days" => 1, "cost" => 3500),
    "Conway" => array("days" => 2, "cost" => 2800),
    "FedEx"  => array("days" => 4, "cost" => 900)
);    

$times = 0;
$totalDays = 9999999;

print "<h1>Shippers to Choose From:</h1><pre>";
print_r($shippers);
print "</pre><br />";

while($totalDays > $maxDays && $times < 500){
            $totalDays = 0;
            $times++;
            $worstShipper = null;
            $longestShippers = null;
            $cheapestShippers = null;

            foreach($shippers as $legName => $leg){
                //find longest shipment for each leg (in terms of days)
                unset($longestShippers[$legName]);
                $longestDays = null;        

                if(count($leg) > 1){
                    foreach($leg as $shipperName => $shipper){
                        if(empty($longestDays) || $shipper["days"] > $longestDays){
                            $longestShippers[$legName]["days"] = $shipper["days"];
                            $longestShippers[$legName]["cost"] = $shipper["cost"];
                            $longestShippers[$legName]["name"] = $shipperName;
                            $longestDays = $shipper["days"];
                        }
                    }           
                }
            }

            foreach($longestShippers as $leg => $shipper){
                $shipper["totalCost"] = $shipper["days"] * $shipper["cost"];

                //print $shipper["totalCost"] . " &lt;?&gt; " . $worstShipper["totalCost"] . ";";

                if(empty($worstShipper) || $shipper["totalCost"] > $worstShipper["totalCost"]){
                    $worstShipper = $shipper;
                    $worstShipperLeg = $leg;
                }
            }

            //print "worst shipper is: shippers[$worstShipperLeg][{$worstShipper['name']}]" . $shippers[$worstShipperLeg][$worstShipper["name"]]["days"];
            unset($shippers[$worstShipperLeg][$worstShipper["name"]]);

            print "<h1>Next:</h1><pre>";
            print_r($shippers);
            print "</pre><br />";

            foreach($shippers as $legName => $leg){
                //find cheapest shipment for each leg (in terms of cost)
                unset($cheapestShippers[$legName]);
                $lowestCost = null;

                foreach($leg as $shipperName => $shipper){
                    if(empty($lowestCost) || $shipper["cost"] < $lowestCost){
                        $cheapestShippers[$legName]["days"] = $shipper["days"];
                        $cheapestShippers[$legName]["cost"] = $shipper["cost"];
                        $cheapestShippers[$legName]["name"] = $shipperName;
                        $lowestCost = $shipper["cost"];
                    }
                }

                //recalculate days and see if we are under max days...
                $totalDays += $cheapestShippers[$legName]['days'];  
            }
            //print "<h2>totalDays: $totalDays</h2>";
        }

        print "<h1>Chosen Shippers:</h1><pre>";
        print_r($cheapestShippers);
        print "</pre>";

文字通り、各組み合わせを 1 つずつ (一連のループを使用して) 作成し、それぞれの合計「スコア」を合計して、最高のものを見つけるという、ある種のことを実際に行う必要があると思います....

編集:明確にするために、これは「宿題」の課題ではありません(私は学校にいません)。それは私の現在のプロジェクトの一部です。

要件は (いつものように) 常に変化しています。この問題に取り組み始めた時点で現在の制約が与えられていたとしたら、A* アルゴリズムの変形 (またはダイクストラまたは最短経路またはシンプレックスなど) を使用していたでしょう。しかし、すべてが変形し、変化しており、それが私を今いる場所に導きます.

つまり、これまでに行ったすべてのがらくたを忘れて、パス検索アルゴリズムである、使用すべきだとわかっているものを使用する必要があることを意味していると思います。

4

7 に答える 7

8

ダイクストラのような最短パス アルゴリズムの一部を変更して、各パスをコストで重み付けするだけでなく、時間を追跡し、時間がしきい値を超えた場合に特定のパスに沿って進むのを停止することもできます。そのようにして、あなたのしきい値を下回る最も安いものを見つける必要があります

于 2008-08-18T16:52:36.930 に答える
5

あなたが持っているものは「線形計画問題」と呼ばれているようです。また、宿題の問題のようにも聞こえますが、気分を害するものではありません。

LP 問題の古典的な解決策は、「シンプレックス法」と呼ばれます。ググってください。

ただし、その方法を使用するには、要件を説明するために問題を正しく定式化する必要があります。

それでも、セットが非常に小さいため、考えられるすべてのパスを列挙できる場合があります。ただし、そのようなことはスケーリングされません。

于 2008-08-18T16:48:34.660 に答える
5

ダイクストラのアルゴリズムの仕事のように聞こえます:

1959 年にオランダのコンピューター科学者 Edsger Dijkstra によって考案された Dijkstra のアルゴリズム1は、非負のエッジ パス コストを持つグラフの単一ソース最短パス問題を解決し、最短パス ツリーを出力するグラフ検索アルゴリズムです。このアルゴリズムは、ルーティングでよく使用されます。

ウィキペディアの記事にも実装の詳細があります。

于 2008-08-18T16:49:53.160 に答える
3

あらかじめ決められた順序で 5 つの都市を処理するだけでよく、隣接する都市間のルートが 3 つしかないことを知っていれば、力ずくで実行します。エレガントであっても意味がありません。

一方、これが宿題であり、実際にスケーリングできるアルゴリズムを作成することになっている場合は、おそらく別のアプローチをとるでしょう。

于 2008-08-18T16:56:02.243 に答える
2

Baltimark が言ったように、これは基本的に線形計画問題です。荷送人の係数 (含まれている場合は 1、含まれていない場合は 0) のみが各レッグの (バイナリ) 整数でない場合、これはより簡単に解決できます。ここで、問題が NP 困難であるため、いくつかの (バイナリ) 整数線形計画法 (ILP) ヒューリスティックを見つける必要があります。リンクについては、ウィキペディアの整数線形計画法を参照してください。私の線形プログラミング コースでは、少なくともBranch and boundを使用しました。

実際、考えてみると、この特別なケースは実際の ILP がなくても解決できます。日数が <= 5 である限り問題にならないからです。まず、一番安いキャリアを選択することから始めます (Conway 5:1000)。次に、もう一度最も安いものを選択すると、結果として 8 日と 4000 通貨単位が多すぎるため、中止します。他のものも試してみると、すべての結果が 5 日を超えていることがわかります。そのため、最初の選択肢に戻り、2 番目に安いもの (FedEx 2:3000) を試してから、2 番目に高くなり、最後に Fedex が高くなります。これにより、合計 4 日と 9000 通貨単位が得られます。

次に、このコストを使用して、サブツリー ステージの結果コストが既に見つかったものよりも大きくなるツリー内の他の検索を削除し、その時点からそのサブツリーを検索しないままにすることができます。これは、コストが負にならない場合にここで行うように、サブツリーでの検索がより良い結果をもたらさないことがわかっている場合にのみ機能します。

このとりとめのないことが少し役立つことを願っています:)。

于 2008-09-19T19:52:57.623 に答える
2

これはナップザックの問題です。重量は輸送中の日数で、利益は 5000 ドル (レッグのコスト) になるはずです。すべての負のコストを排除し、そこから出発しましょう!

于 2008-08-22T22:04:18.940 に答える
-1

ダイクストラのアルゴリズムは最短経路を見つけるためのものだと思います。

cmccullohは、5 日でそこに到達するという制約を条件として、最小コストを探しています。

したがって、単に最速の方法を見つけたからといって、最安値でそこにたどり着くことはできません。

于 2008-08-18T16:56:10.480 に答える