Birden fazla setleri kümesi verilen en iyi kombinasyonu bulmak

8 Cevap php

Eğer bir sevkiyat var söylüyorlar. Bu nokta B, C noktasına noktasından B noktasına gitmek gerekir ve nihayet Bunu mümkün para az miktarda beş gün içinde oraya gerekir D. işaret C etmektedir. Her bacak için üç olası nakliyatçılar, kendi farklı zaman ve her bacak için maliyet her vardır:

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
                )

        )

)

Nasıl programlı iyi kombinasyonunu bulma konusunda gitmek?

Benim en iyi girişimi şimdiye kadar (üçüncü veya dördüncü algoritması):

  1. Her bacak için uzun gönderen bul
  2. En "pahalı" bir eleyin
  3. Her bacak için ucuz gönderen bul
  4. Toplam maliyeti & hesaplayın günler
  5. Gün kabul edilebilir ise, bitirmek, başka goto 1

PHP hızlı bir alay-up (aşağıda deney dizisi tıkırında çalışıyor, ancak yukarıdaki deney dizisi ile deneyin, eğer doğru kombinasyonunu bulmak unutmayın):

$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>";

Aslında ben tam anlamıyla her kombinasyon (döngüler bir dizi ile) tek tek yapmak ve her birinin toplam "puan" eklemek, ve en iyisini bulmak şey çeşit yapmak zorunda olabilir düşünüyorum ....

EDIT: To clarify, this isn't a "homework" assignment (I'm not in school). It is part of my current project at work.

(Her zaman olduğu gibi) gereksinimleri sürekli değişiyor. Ben bu sorun üzerinde çalışmaya başladı anda geçerli kısıtlamaları verildi, ben A * algoritması bir varyasyonunu kullanıyor olurdu (veya Dijkstra'nın ya da kısa yol veya simplex veya şey). Ama her şey geçişin ve değişen, ve ben şu anda kulüpler nerede bana getiriyor olmuştur.

Ben ki ben bu noktaya yapılır ve sadece bir yol bulma algoritması olan, ben gitmek gerektiğini biliyorum ne ile gitmek onca bok unutmak gerekiyor demektir sanırım.

8 Cevap

Dijkstra'nın gibi shortest path algorithms, bazı, maliyet her yolu kilo değil, aynı zamanda zaman takip ve zaman sizin eşiği aşarsa belirli bir yol boyunca gidiyor durdurmak için değiştirebilir. Senin eşiğin altında yol sizi alır ucuz bulmak gerekir

Eğer bir "doğrusal programlama problemi" denir ne gibi sesler. Ayrıca ödev sorun, hiçbir suç gibi geliyor.

LP bir soruna klasik bir çözüm "Tek yöntem" olarak adlandırılır. Google.

Ancak, bu yöntemi kullanmak için, sorunun doğru gereksinimleri tanımlamak için formüle sahip olmalıdır.

Yine de, böyle küçük bir kümesine sahip olduğundan, mümkün olan tüm yolları numaralandırmak mümkün olabilir. Böyle bir şey olsa, ölçek olmaz.

Için bir iş gibi geliyor Dijkstra's algorithm:

1959 yılında Hollandalı bilgisayar bilimcisi Edsger Dijkstra'nın tarafından tasarlanmıştı Dijkstra'nın algoritması, [1], bir kısa yol ağacı çıktısı, negatif olmayan kenar yol masrafları ile bir grafik için tek kaynaklı en kısa yol problemi çözen bir grafik arama algoritması olduğunu. Bu algoritma genellikle yönlendirme kullanılır.

Wikipedia makalesinde uygulama detayları da vardır.

Ben sadece önceden belirlenmiş bir sırayla, 5 şehirde uğraşmak zorunda, ve biliyordu ise komşu şehirler arasında sadece 3 yol vardı, onu kaba kuvvet olur. Zarif olmanın anlamı yok.

Öte yandan, bu bir ödev vardı ve ben aslında ölçek verebilecek bir algoritma üretmek gerekiyordu, eğer, muhtemelen farklı bir yaklaşım olur.

As Baltimark said, this is basically a Linear programming problem. If only the coefficients for the shippers (1 for included, 0 for not included) were not (binary) integers for each leg, this would be more easily solveable. Now you need to find some (binary) integer linear programming (ILP) heuristics as the problem is NP-hard. See Wikipedia on integer linear programming for links; on my linear programming course we used at least Branch and bound.

Aslında şimdi düşünüyorum da, bu özel durum günlerin miktarı gibi gerçek İLP olmadan çözülebilir olduğu sürece <= 5. Şimdi ilk seçim için ucuz taşıyıcı seçerek başlayabilirsiniz (Conway 5:1000) olarak farketmez . Sonra çok fazla bu yüzden bu iptal olan 8 gün ve 4000 para birimi çıkan, yine ucuz seçin. Diğerlerini deneyerek de görüyoruz ki tüm sonuçları gün> 5 yüzden geri ilk seçim ve son olarak ikinci (FedEx 2:3000) ucuz ve daha sonra up ikinci ve FedEx deneyin. Bu bize 4 gün ve 9000 para birimlerinin toplam verir.

We then could use this cost to prune other searches in the tree that would by some subtree-stage result costs larger that the one we've found already and leave that subtree unsearched from that point on. This only works as long as we can know that searching in the subtree will not produce a better results, as we do here when costs cannot be negative.

Bu başıboş :) biraz yardımcı umuyoruz.

Bu knapsack problem olduğunu. Ağırlıklar transit günler ve kar $ 5000 olmalı - bacak maliyeti. Tüm olumsuz maliyetleri ortadan kaldırmak ve oradan gitmek!

Bu konu gerçekten enayi.

Baltimark 16:48 birinde saat 16:56 ama yazı ile esentially hakkıdır. Neden onun doğru cevap downmoded ve yanlış cevap (ki bir cevap olsaydı) upmoded oldu? Bu çantanın, evet, bir çeşididir. Ayrıca, mevcut sınırları ile, o kaba kuvvet kolay. Burada Dijkstra'nın algo adapte sanmıyorum.

Kevin Sheffield cevabı çok muğlak. O kısa maliyet tutmak ve kısa pahalıya hızlı güzergahı FOST gerekiyordu, o ölü yanlıştır. Her güzergah uzunluğu için kısa maliyeti hatırlamıyorum Aksi takdirde, eğer esentially bir sırt çantası var.

Urgh.

Ben Dijkstra'nın algoritması bir kısa yolu bulmak için olduğunu düşünüyorum.

cmcculloh o 5 gün orada onu alır kısıtı az maliyetli konu arıyor.

Yani, sadece hızlı yol bulma oraya onu ucuz almazsınız, ve, en ucuz için getting zaman gerekli miktarda orada almazsınız.