100個の移動するターゲット間の最短経路を見つけるにはどうすればよいですか?(ライブデモが含まれています。)


89

バックグラウンド

次の図は問題を示しています。 square_grid_with_arrows_giving_directions

赤い丸をコントロールできます。ターゲットは青い三角形です。黒い矢印は、ターゲットが移動する方向を示します。

最低限のステップですべてのターゲットを収集したい。

ターンごとに、左/右/上または下に1ステップ移動する必要があります。

ボードに表示されている指示に従って、ターゲットを1回転するたびに1ステップ移動します。

デモ

この問題の再生可能なデモをGoogle appengineで公開しました

これは私の現在のアルゴリズムが最適ではないことを示しているので、誰かが目標スコアを上回ることができるかどうか非常に興味があります。(これを管理したら、おめでとうメッセージが表示されます!)

問題

私の現在のアルゴリズムは、ターゲットの数に非常によく対応していません。時間は指数関数的に増加し、16匹の魚ではすでに数秒です。

32 * 32のボードサイズと100個の移動ターゲットでの答えを計算したいと思います。

質問

すべてのターゲットを収集するための最小ステップ数を計算するための効率的なアルゴリズム(理想的にはJavaScript)とは何ですか?

私が試したこと

私の現在のアプローチはメモ化に基づいていますが、それは非常に遅く、常に最良のソリューションを生成するかどうかはわかりません。

「特定のターゲットのセットを収集して特定のターゲットに到達するための最小ステップ数はいくつですか?」の副問題を解決します。

サブ問題は、前のターゲットが訪問したことについての各選択肢を調べることにより、再帰的に解決されます。以前のターゲットのサブセットをできるだけ早く収集し、最終的な位置から現在のターゲットにできるだけ早く移動することが常に最適であると思います(ただし、これが有効な仮定であるかどうかはわかりません)。

これにより、n * 2 ^ n状態が計算され、非常に急速に増加します。

現在のコードを以下に示します。

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;
}

私が考えたこと

私が疑問に思ったいくつかのオプションは次のとおりです。

  1. 中間結果のキャッシュ。距離計算は多くのシミュレーションを繰り返し、中間結果はキャッシュされる可能性があります。
    しかし、これで指数関数的な複雑さがなくなるとは思いません。

  2. A *検索アルゴリズム。ただし、適切な許容ヒューリスティックがどのようなものであり、これが実際にどの程度効果的であるかは私には明らかではありません。

  3. 巡回セールスマン問題の優れたアルゴリズムを調査し、それらがこの問題に当てはまるかどうかを確認します。

  4. 問題がNP困難であることを証明しようとするため、最適な答えを探すことは合理的ではありません。


1
私は#4に行き、続いて#3に行きます。十分に大きなボードがあれば、TSPを非常によく模倣します。
John Dvorak

2
私の知る限り、TSPはマンハッタンメトリック(正方グリッド)と同様にユークリッドメトリックでもNP困難です。
John Dvorak

1
単純なツリー検索でそれを行う場合、はい、それは指数関数になります。ただし、各ステップで適切なヒューリスティックを見つけることができる場合、それは本当に最適ではないかもしれませんが、非常に良いかもしれません。ヒューリスティックの1つは、現在の魚のセットを調べることです。どれが最も早く到達できますか?二次ヒューリスティックは、どの2魚を最も早く到達できますか?
マイクダンラベイ2013年

2
@MikeDunlaveyは貪欲なTSPアルゴリズムに対応し、実際には非常にうまく機能します。最も近い魚に行くのは良い考えのようです
John Dvorak

1
コンテンツと構造の両方について、最近見た中で最高の質問の1つに+1を付けます。
surfitscrollit 2013年

回答:


24

文献を検索しましたか?私はあなたの問題を分析しているように見えるこれらの論文を見つけました:

更新1:

上記の2つの論文は、ユークリッドメトリックの線形移動に集中しているようです。


ありがとうございました。それらの論文を見たことがありませんでしたが、非常に関連性が高いようです。私の場合に遺伝的アルゴリズムを機能させるように適応できるかどうかを確認し、それを総当たりのアプローチの結果と比較します。
Peter de Rivaz 2013年

13

貪欲な方法

コメントで提案されている1つのアプローチは、最初に最も近いターゲットに移動することです。

ここでは、この貪欲な方法計算されたコストを含むデモのバージョンを公開しました

コードは次のとおりです。

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個のターゲットの場合、最適距離の約2倍ですが、場合によってはそれよりはるかに多く(例:* 4)、最適距離に到達することもあります。

このアプローチは非常に効率的であるため、答えを改善するためにいくつかのサイクルを用意することができます。

次に、アリのコロニー法を使用して、ソリューション空間を効果的に探索できるかどうかを検討しています。

アリコロニー法

アントコロニー法では、この問題のために顕著うまく動作するように思えます。この回答のリンクは、貪欲とアリの両方のコロニー法を使用した場合の結果を比較します。

アリは、フェロモンの現在のレベルに基づいて、確率的にルートを選択するという考えです。10回の試行ごとに、発見した最短のトレイルに沿って追加のフェロモンを配置します。

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;
}

結果

10アリの100回の繰り返しを使用するこのアリコロニー法は、依然として非常に高速であり(徹底的な検索の3700msと比較して、16ターゲットでは37ms)、非常に正確に見えます。

次の表は、16個のターゲットを使用した10回の試行の結果を示しています。

   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

antメソッドは、貪欲なものよりも大幅に優れており、最適に非常に近いことがよくあります。


いいね。完全な検索ではまだ最適な結果が得られない可能性があります(または、その扱いにくいためにおそらくまったくないかもしれません)。しかし、同じ数のターゲットで、蟻のコロニーがボードサイズ(32x32)でスケーリングする様子を見るのは興味深いでしょう。
timxyz 2013年

8

問題は、一般化された巡回セールスマン問題の観点から表され、その後、従来の巡回セールスマン問題に変換されます。これはよく研究された問題です。OPの問題に対する最も効率的な解決策はTSPに対する解決策よりも効率的ではない可能性がありますが、決して確実ではありません(おそらく、より迅速な解決策を可能にするOPの問題構造のいくつかの側面を活用できていません。 、その周期的な性質など)。どちらにしても、それは良い出発点です。

C. Noon&J.Beanから、一般化した巡回セールスマン問題の効率的な変換

一般化巡回セールスマン問題(GTSP)は、選択と順序の決定を含む問題のために有用なモデルです。問題の非対称バージョンは、ノードN、アークAを接続する有向グラフ、および対応するアークコストcのベクトルで定義されます。ノードは、相互に排他的で完全なm個のノードセットに事前にグループ化されています。接続アークは、異なるセットに属するノード間でのみ定義されます。つまり、セット内アークはありません。定義された各アークには、対応する負でないコストがあります。GTSPは、各ノードセットから正確に1つのノードを含む最小コストのm-arcサイクルを見つける問題として説明できます。

OPの問題について:

  • の各メンバーはN、特定の時間における特定の魚の位置です。これを表し(x, y, t)、ここで、(x, y)グリッド座標であり、t魚はこの座標にされる時間です。OPの例の左端の魚の場合、これらの最初のいくつか(1ベース)は次のとおりです。(3, 9, 1), (4, 9, 2), (5, 9, 3)です。魚が右に移動するとき。
  • Nの任意のメンバーについてfish(n_i)、ノードによって表される魚のIDを返します。Nの任意の2つのメンバーについて、2 manhattan(n_i, n_j)つのノード間のマンハッタン距離を計算できます。time(n_i, n_j、ノード間の時間オフセット。
  • 互いに素なサブセットの数mは、魚の数と同じです。ばらばらのサブセットS_iは、fish(n) == i
  • 2つのノードの場合、iとのj fish(n_i) != fish(n_j)間にアークがiありますjます。
  • ノードiとノードjの間のコストはtime(n_i, n_j)であるか、未定義の場合time(n_i, n_j) < distance(n_i, n_j)(つまり、おそらく時間的に後退しているため、魚がそこに到着する前に場所に到達できない)です。この後者のタイプのアークは削除できます。
  • 他のすべてのノードに対して、アークとコストを持つプレーヤーの場所を表すノードを追加する必要があります。

この問題を解決すると、最小のコスト(つまり、すべての魚を取得するための最小の時間)でパスの各ノードサブセット(つまり、各魚が一度取得される)に1回アクセスすることになります。

このペーパーでは、上記の定式化を従来の巡回セールスマン問題に変換し、その後既存の手法で解決または近似する方法について説明します。詳細については読みませんでしたが、効率的であると宣言されている方法でこれを行っている別の論文がこれです。

複雑さには明らかな問題があります。特に、ノードスペースは無限です。これは、特定の期間までのノードを生成するだけで軽減できます。場合tのためにノードを生成するためのタイムステップの数で、f魚の数であり、そのノードのスペースの大きさになりますt * f。ある時点でのノードjは、多くても(f - 1) * (t - j)外向きの弧を持ちます(時間を遡ったり、独自のサブセットに移動したりできないため)。アークの総数は次の順序になりますt^2 * f^2ます。魚の進路が最終的に周期的であるという事実を利用するために、弧の構造はおそらく整頓することができます。魚は、サイクルの長さの最も一般的な分母ごとに構成を繰り返すため、おそらくこの事実を使用できます。

TSPについて、これが実現可能かどうかを判断するのに十分な知識がありません。投稿された問題が必ずしも NP困難であることを意味しているとは思いません...しかし、これは最適なソリューションまたは境界のあるソリューションを見つけるための1つのアプローチです。


ありがとう、これは私にとって新しいものであり、非常に興味深いものです。この変換をChristofidesアルゴリズムと組み合わせて使用​​して、最適値の3/2の近似係数内で効率的に解を見つけることができると思います。動作するようになったら、生成されたルートをデモページに追加します。
Peter de Rivaz

ああ、私の計画には問題があると思います。私の元の問題は、メトリックの適切な不等式を満たす完全なグラフですが、説明されている変換の結果は不完全なグラフになり、Christofidesアルゴリズムが適用されなくなります。とにかく面白い視点をありがとう。
Peter de Rivaz

はい、三角形の不等式はもはや成立しないことを言及するのを忘れました。ただし、ヒューリスティックソリューションやより一般的な近似の出発点としては適しています。
timxyz 2013年

1

別のアプローチは次のようになると思います:

ウィキペディアの引用:

数学では、ボロノイ図は空間をいくつかの領域に分割する方法です。ポイントのセット(シード、サイト、またはジェネレーターと呼ばれます)は事前に指定されており、各シードには、他のシードよりもそのシードに近いすべてのポイントで構成される対応する領域があります。

したがって、ターゲットを選択し、いくつかのステップのパスに従って、そこにシードポイントを設定します。他のすべてのターゲットでもこれを行うと、ボロニ図が表示されます。現在のエリアに応じて、そのシードポイントに移動します。ビオラ、あなたは最初の魚を手に入れた。すべてを手に入れるまで、このステップを繰り返します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.