100 hareketli hedef arasındaki en kısa yolu nasıl bulabilirim? (Canlı demo dahildir.)


89

Arka fon

Bu resim sorunu göstermektedir: square_grid_with_arrows_giving_directions

Kırmızı daireyi kontrol edebilirim. Hedefler mavi üçgenler. Siyah oklar, hedeflerin hareket edeceği yönü gösterir.

Tüm hedefleri minimum adım sayısında toplamak istiyorum.

Her dönüşte 1 adım sola / sağa / yukarı veya aşağı hareket etmeliyim.

Her dönüşte hedefler ayrıca tahtada gösterilen talimatlara göre 1 adım hareket edecektir.

Demo

Sorunun oynanabilir bir demosunu burada Google uygulama motoruna koydum .

Mevcut algoritmamın yetersiz olduğunu göstereceğinden, herhangi biri hedef puanı geçebilirse çok ilgilenirim. (Bunu yönetirseniz bir tebrik mesajı yazdırılmalıdır!)

Sorun

Mevcut algoritmam hedeflerin sayısına göre gerçekten kötü bir şekilde ölçekleniyor. Zaman katlanarak artar ve 16 balık için zaten birkaç saniyedir.

32 * 32 tahta boyutları ve 100 hareketli hedef için cevabı hesaplamak istiyorum.

Soru

Tüm hedefleri toplamak için minimum adım sayısını hesaplamak için etkili bir algoritma (ideal olarak Javascript'te) nedir?

Ne denedim

Şu anki yaklaşımım ezbere dayanıyor ama çok yavaş ve her zaman en iyi çözümü üretip üretmeyeceğini bilmiyorum.

"Belirli bir hedef kümesini toplamak ve belirli bir hedefe ulaşmak için gereken minimum adım sayısı nedir?" Alt problemini çözüyorum.

Alt problem, önceki hedefin ziyaret ettiği her bir seçim incelenerek özyinelemeli olarak çözülür. Önceki hedef alt kümesini olabildiğince çabuk toplayıp, sonlandırdığınız konumdan mevcut hedefe mümkün olan en kısa sürede geçmenin her zaman en uygun olduğunu varsayıyorum (bunun geçerli bir varsayım olup olmadığını bilmeme rağmen).

Bu, çok hızlı büyüyen n * 2 ^ n durumlarının hesaplanmasına neden olur.

Mevcut kod aşağıda gösterilmiştir:

var DX=[1,0,-1,0];
var DY=[0,1,0,-1]; 

// Return the location of the given fish at time t
function getPt(fish,t) {
  var i;
  var x=pts[fish][0];
  var y=pts[fish][1];
  for(i=0;i<t;i++) {
    var b=board[x][y];
    x+=DX[b];
    y+=DY[b];
  }
  return [x,y];
}

// Return the number of steps to track down the given fish
// Work by iterating and selecting first time when Manhattan distance matches time
function fastest_route(peng,dest) {
  var myx=peng[0];
  var myy=peng[1];
  var x=dest[0];
  var y=dest[1];
  var t=0;
  while ((Math.abs(x-myx)+Math.abs(y-myy))!=t) {
    var b=board[x][y];
    x+=DX[b];
    y+=DY[b];
    t+=1;
  }
  return t;
}

// Try to compute the shortest path to reach each fish and a certain subset of the others
// key is current fish followed by N bits of bitmask
// value is shortest time
function computeTarget(start_x,start_y) {
  cache={};
  // Compute the shortest steps to have visited all fish in bitmask
  // and with the last visit being to the fish with index equal to last
  function go(bitmask,last) {
    var i;
    var best=100000000;
    var key=(last<<num_fish)+bitmask;
    if (key in cache) {
      return cache[key];
    }
    // Consider all previous positions
    bitmask -= 1<<last;
    if (bitmask==0) {
      best = fastest_route([start_x,start_y],pts[last]);
    } else {
      for(i=0;i<pts.length;i++) {
        var bit = 1<<i;
        if (bitmask&bit) {
          var s = go(bitmask,i);   // least cost if our previous fish was i
          s+=fastest_route(getPt(i,s),getPt(last,s));
          if (s<best) best=s;
        }
      }
    }
    cache[key]=best;
    return best;
  }
  var t = 100000000;
  for(var i=0;i<pts.length;i++) {
    t = Math.min(t,go((1<<pts.length)-1,i));
  }
  return t;
}

Ne düşündüm

Merak ettiğim bazı seçenekler:

  1. Ara sonuçların önbelleğe alınması. Mesafe hesaplaması birçok simülasyonu tekrar eder ve ara sonuçlar önbelleğe alınabilir.
    Ancak bunun üstel karmaşıklığa sahip olmasını engelleyeceğini sanmıyorum.

  2. Bir A * arama algoritması, uygun bir kabul edilebilir buluşsal yöntemin ne olacağı ve bunun pratikte ne kadar etkili olacağı benim için açık olmasa da.

  3. Gezgin satıcı problemi için iyi algoritmaları araştırmak ve bu probleme uygulayıp uygulamadıklarına bakmak.

  4. Sorunun NP-zor olduğunu ve dolayısıyla bunun için en uygun cevabı aramak mantıksız olduğunu kanıtlamaya çalışmak.


1
4 numaraya ve ardından 3 numaraya giderdim: Yeterince büyük panolarla TSP'yi oldukça iyi taklit eder.
John Dvorak

2
Bildiğim kadarıyla TSP, öklid metriği ve manhattan metriği (kare ızgara) ile NP-zordur.
John Dvorak

1
Basit ağaç arama ile yaparsanız, evet, üstel olacaktır. Bununla birlikte, her adımda iyi bir buluşsal yöntem bulabilirseniz, bu gerçekten optimal olmayabilir, ancak çok iyi olabilir. Olası bir buluşsal yöntem, mevcut balık kümesine bakıldığında hangisine en hızlı şekilde ulaşılabildi? İkincil bir buluşsal yöntem, en hızlı şekilde hangi 2 balığa ulaşabilirim?
Mike Dunlavey

2
@MikeDunlavey açgözlü TSP algoritmasına karşılık gelir ve pratikte çok iyi çalışır. En yakın balığa gitmek iyi bir fikir gibi görünüyor
John Dvorak

1
Hem içerik hem de yapı açısından son zamanlarda gördüğüm en iyi sorulardan biri için +1.
surfitscrollit

Yanıtlar:


24

Literatürü incelediniz mi? Sorununuzu analiz ediyor gibi görünen şu kağıtları buldum:

GÜNCELLEME 1:

Yukarıdaki iki makale, öklid metriği için doğrusal harekete odaklanıyor gibi görünüyor.


Teşekkürler - O kağıtları görmemiştim ama çok alakalı görünüyorlar. Genetik algoritmayı benim durumumda çalışacak şekilde uyarlayıp, bunu kaba kuvvet yaklaşımının sonuçlarıyla karşılaştırıp karşılaştırmayacağımı göreceğim.
Peter de Rivaz

13

Açgözlü yöntem

Yorumlarda önerilen yaklaşımlardan biri, önce en yakın hedefe gitmektir.

Demonun bu açgözlü yöntemle hesaplanan maliyeti içeren bir versiyonunu buraya koydum .

Kod:

function greedyMethod(start_x,start_y) {
  var still_to_visit = (1<<pts.length)-1;
  var pt=[start_x,start_y];
  var s=0;
  while (still_to_visit) {
    var besti=-1;
    var bestc=0;
    for(i=0;i<pts.length;i++) {
      var bit = 1<<i;
      if (still_to_visit&bit) {
        c = fastest_route(pt,getPt(i,s));
        if (besti<0 || c<bestc) {
          besti = i;
          bestc = c;
        }
      }
    }
    s+=c;
    still_to_visit -= 1<<besti;
    pt=getPt(besti,s);
  }
  return s;
}

10 hedef için optimum mesafenin yaklaşık iki katıdır, ancak bazen çok daha fazladır (örn. * 4) ve hatta bazen optimum olana bile ulaşır.

Bu yaklaşım çok etkilidir, bu nedenle cevabı iyileştirmek için bazı döngülere sahip olabilirim.

Daha sonra çözüm uzayını etkili bir şekilde keşfedip keşfedemeyeceklerini görmek için karınca kolonisi yöntemlerini kullanmayı düşünüyorum.

Karınca kolonisi yöntemi

Bir Karınca kolonisi yöntemi , bu sorun için oldukça iyi çalışıyor gibi görünüyor. Bu cevaptaki bağlantı şimdi hem açgözlü hem de karınca kolonisi yöntemini kullanırken sonuçları karşılaştırıyor.

Buradaki fikir, karıncaların olasılıklı olarak mevcut feromon seviyesine göre rotalarını seçmeleridir. Her 10 denemeden sonra, buldukları en kısa iz boyunca ek feromon yatırıyoruz.

function antMethod(start_x,start_y) {
  // First establish a baseline based on greedy
  var L = greedyMethod(start_x,start_y);
  var n = pts.length;
  var m = 10; // number of ants
  var numrepeats = 100;
  var alpha = 0.1;
  var q = 0.9;
  var t0 = 1/(n*L);

  pheromone=new Array(n+1); // entry n used for starting position
  for(i=0;i<=n;i++) {
    pheromone[i] = new Array(n);
    for(j=0;j<n;j++)
      pheromone[i][j] = t0; 
  }

  h = new Array(n);
  overallBest=10000000;
  for(repeat=0;repeat<numrepeats;repeat++) {
    for(ant=0;ant<m;ant++) {
      route = new Array(n);
      var still_to_visit = (1<<n)-1;
      var pt=[start_x,start_y];
      var s=0;
      var last=n;
      var step=0;
      while (still_to_visit) {
        var besti=-1;
        var bestc=0;
        var totalh=0;
        for(i=0;i<pts.length;i++) {
          var bit = 1<<i;
          if (still_to_visit&bit) {
            c = pheromone[last][i]/(1+fastest_route(pt,getPt(i,s)));
            h[i] = c;
            totalh += h[i];
            if (besti<0 || c>bestc) {
              besti = i;
              bestc = c;
            }
          }
        }
        if (Math.random()>0.9) {
          thresh = totalh*Math.random();
          for(i=0;i<pts.length;i++) {
            var bit = 1<<i;
            if (still_to_visit&bit) {
              thresh -= h[i];
              if (thresh<0) {
                besti=i;
                break;
              }
            }
          }
        }
        s += fastest_route(pt,getPt(besti,s));
        still_to_visit -= 1<<besti;
        pt=getPt(besti,s);
        route[step]=besti;
        step++;
        pheromone[last][besti] = (1-alpha) * pheromone[last][besti] + alpha*t0;
        last = besti;
      }
      if (ant==0 || s<bestantscore) {
        bestroute=route;
        bestantscore = s;
      }
    }
    last = n;
    var d = 1/(1+bestantscore);
    for(i=0;i<n;i++) {
      var besti = bestroute[i];
      pheromone[last][besti] = (1-alpha) * pheromone[last][besti] + alpha*d;
      last = besti;
    }
    overallBest = Math.min(overallBest,bestantscore);
  }
  return overallBest;
}

Sonuçlar

10 karıncanın 100 tekrarını kullanan bu karınca kolonisi yöntemi hala çok hızlıdır (kapsamlı arama için 3700 ms'ye kıyasla 16 hedef için 37 ms) ve çok doğru görünüyor.

Aşağıdaki tablo, 16 hedef kullanan 10 denemenin sonuçlarını göstermektedir:

   Greedy   Ant     Optimal
   46       29      29
   91       38      37
  103       30      30
   86       29      29
   75       26      22
  182       38      36
  120       31      28
  106       38      30
   93       30      30
  129       39      38

Karınca yöntemi, açgözlülükten önemli ölçüde daha iyi görünür ve çoğu zaman en iyiye çok yakındır.


Güzel. Henüz kapsamlı aramadan en iyi sonuçları alamayabilirsiniz (veya muhtemelen inatçı olmamasından dolayı asla!), Ancak karınca kolonisinin tahta boyutunda (32x32) aynı sayıda hedefle nasıl ölçeklendiğini görmek ilginç olurdu.
timxyz

8

Sorun, Genelleştirilmiş Seyahat Eden Satıcı Problemi açısından temsil edilebilir ve daha sonra geleneksel bir Seyahat Eden Satıcı Problemine dönüştürülebilir. Bu, üzerinde iyi çalışılmış bir sorundur. OP'nin sorununa yönelik en etkili çözümlerin TSP'ye çözümlerden daha verimli olmaması, ancak hiçbir şekilde kesin olmaması olasıdır (OP'nin problem yapısının daha hızlı bir çözüme izin verecek bazı yönlerinden muhtemelen yararlanamıyorum. döngüsel doğası gibi). Her iki durumda da iyi bir başlangıç ​​noktasıdır.

Gönderen C. Noon & J.Bean, Genelleştirilmiş Gezgin Satıcı Sorunu ve Etkin Bir Dönüşümün :

Genelleştirilmiş Gezgin satıcı sorun (GTSP) seçimi ve dizinin kararlar içeren problemleri için uygun bir modeldir. Sorunun asimetrik versiyonu, N düğümleri olan, A yaylarını ve karşılık gelen yay maliyetlerinin c vektörünü bağlayan yönlendirilmiş bir grafik üzerinde tanımlanır. Düğümler, karşılıklı olarak birbirini dışlayan ve kapsamlı düğüm kümeleri halinde önceden gruplanmıştır. Bağlantı yayları, yalnızca farklı kümelere ait düğümler arasında tanımlanır, yani, küme içi yaylar yoktur. Tanımlanan her ark, karşılık gelen negatif olmayan bir maliyete sahiptir. GTSP, her düğüm kümesinden tam olarak bir düğüm içeren minimum maliyetli bir m-yay döngüsü bulma sorunu olarak ifade edilebilir .

OP'nin sorunu için:

  • Her üye Nbelirli bir balığın belirli bir zamandaki konumudur. Bunu (x, y, t), (x, y)ızgara koordinatı nerede tve balığın bu koordinatta olacağı zaman olarak temsil edin. OP örneğindeki en soldaki balıklar için, bunlardan ilk birkaçı (1 temelli): (3, 9, 1), (4, 9, 2), (5, 9, 3)balık sağa doğru hareket ederken.
  • Herhangi bir N üyesi fish(n_i)için düğüm tarafından temsil edilen balığın kimliğini döndürelim. N'nin herhangi iki üyesi manhattan(n_i, n_j)için, iki düğüm arasındaki manhattan mesafesini ve time(n_i, n_j) düğümler arasındaki zaman kaymasını hesaplayabiliriz .
  • Ayrık alt kümelerin sayısı m, balık sayısına eşittir. Ayrık alt küme S_i, yalnızca bunlara ait olan düğümlerden oluşacaktır fish(n) == i.
  • İki düğüm için ive j fish(n_i) != fish(n_j)sonra ive arasında bir yay varsa j.
  • İ düğümü ile j düğümü arasındaki maliyet time(n_i, n_j)tanımsızdır veya tanımsızdır time(n_i, n_j) < distance(n_i, n_j)(yani konuma balık oraya varmadan ulaşılamaz, belki de zamanda geriye doğru olduğu için). Bu son tipteki yaylar kaldırılabilir.
  • Oynatıcının konumunu yaylarla ve diğer tüm düğümlere maliyetlerle temsil eden fazladan bir düğümün eklenmesi gerekecektir.

Bu problemi çözmek, daha sonra minimum maliyetle (yani tüm balıkların elde edilmesi için minimum süre) bir yol için her düğüm alt kümesine (yani her balık bir kez elde edilir) tek bir ziyaretle sonuçlanacaktır.

Kağıt, yukarıdaki formülasyonun geleneksel bir Seyahat Eden Satıcı Problemine nasıl dönüştürülebileceğini ve daha sonra mevcut tekniklerle nasıl çözülebileceğini veya yaklaştırılabileceğini anlatmaya devam ediyor. Ayrıntıları okumadım ama bunu verimli olduğunu ilan ettiği şekilde yapan başka bir kağıt da bu .

Karmaşıklıkla ilgili bariz sorunlar var. Özellikle düğüm uzayı sonsuzdur! Bu, yalnızca belirli bir zaman ufkuna kadar düğümler oluşturarak hafifletilebilir. Eğer tiçin düğüm oluşturmak için dilimler sayısıdır ve fbalık sayısı daha sonra düğüm alan büyüklüğünde olacak t * f. Zamanda bir düğüm en jçok (f - 1) * (t - j)giden yaylara sahip olacaktır (zamanda veya kendi alt kümesine geri dönemeyeceği için). Toplam yay sayısı yay sırasına göre olacaktır t^2 * f^2. Balık yollarının nihayetinde döngüsel olması gerçeğinden yararlanmak için yay yapısı muhtemelen düzeltilebilir. Balık, döngü uzunluklarının en küçük ortak paydalarında bir kez konfigürasyonunu tekrarlayacaktır, böylece belki de bu gerçek kullanılabilir.

Bunun uygulanabilir olup olmadığını söyleyecek kadar TSP hakkında yeterli bilgim yok ve bunun, yayınlanan sorunun mutlaka NP-zor olduğu anlamına geldiğini düşünmüyorum ... ama bu, optimal veya sınırlı bir çözüm bulmaya yönelik bir yaklaşım .


Teşekkürler, bu benim için yeni ve çok ilginç. Sanırım bu dönüşümü Christofides algoritmasıyla birlikte optimalin 3 / 2'si kadar bir yaklaşım faktörü içinde verimli bir şekilde bir çözüm bulmak için kullanabilmeliyim. Çalışmasını sağlarsam, üretilen yolları demo sayfasına ekleyeceğim.
Peter de Rivaz

Ah, planımla ilgili bir sorun olduğunu düşünüyorum, çünkü orijinal problemim metrikte uygun bir eşitsizliği karşılayan eksiksiz bir grafik olsa da, açıklanan dönüşüm eksik bir grafikle sonuçlanıyor ve bu nedenle Christofides algoritması artık geçerli değil. Yine de ilginç bakış açısı için teşekkürler.
Peter de Rivaz

Evet, üçgen eşitsizliğinin artık geçerli olmadığını söylemeyi unuttum. Bununla birlikte, sezgisel çözümler ve daha genel yaklaşımlar için iyi bir başlangıç ​​noktasıdır.
timxyz

1

Sanırım başka bir yaklaşım:

Alıntı Wikipedia:

Matematikte bir Voronoi diyagramı, alanı birkaç bölgeye bölmenin bir yoludur. Önceden bir dizi nokta (tohumlar, siteler veya oluşturucular olarak adlandırılır) belirlenir ve her bir tohum için, o tohuma diğerlerinden daha yakın olan tüm noktalardan oluşan karşılık gelen bir bölge olacaktır.

Böylece bir hedef seçersiniz, bazı adımlar için yolunu takip edersiniz ve orada bir tohum noktası belirlersiniz. Bunu diğer tüm hedefler için de yapın ve bir voroni diyagramı elde edin. Hangi bölgede olduğunuza bağlı olarak, onun başlangıç ​​noktasına gidersiniz. Viola, ilk balığı aldın. Şimdi hepsini öğrenene kadar bu adımı tekrarlayın.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.