バックグラウンド
次の図は問題を示しています。
赤い丸をコントロールできます。ターゲットは青い三角形です。黒い矢印は、ターゲットが移動する方向を示します。
最低限のステップですべてのターゲットを収集したい。
ターンごとに、左/右/上または下に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;
}
私が考えたこと
私が疑問に思ったいくつかのオプションは次のとおりです。
中間結果のキャッシュ。距離計算は多くのシミュレーションを繰り返し、中間結果はキャッシュされる可能性があります。
しかし、これで指数関数的な複雑さがなくなるとは思いません。A *検索アルゴリズム。ただし、適切な許容ヒューリスティックがどのようなものであり、これが実際にどの程度効果的であるかは私には明らかではありません。
巡回セールスマン問題の優れたアルゴリズムを調査し、それらがこの問題に当てはまるかどうかを確認します。
問題がNP困難であることを証明しようとするため、最適な答えを探すことは合理的ではありません。