sfondo
Questa immagine illustra il problema:
Posso controllare il cerchio rosso. Gli obiettivi sono i triangoli blu. Le frecce nere indicano la direzione in cui si muoveranno i bersagli.
Voglio raccogliere tutti i target nel numero minimo di passaggi.
Ogni turno devo muovermi di 1 passo a sinistra / destra / su o giù.
Ogni turno i bersagli si muoveranno anche di 1 passo secondo le direzioni mostrate sul tabellone.
Demo
Ho messo su una demo giocabile del problema qui su appengine di Google .
Sarei molto interessato se qualcuno potesse battere il punteggio target in quanto ciò dimostrerebbe che il mio algoritmo attuale non è ottimale. (Se lo gestisci, dovrebbe essere stampato un messaggio di congratulazioni!)
Problema
Il mio attuale algoritmo scala davvero male con il numero di bersagli. Il tempo aumenta in modo esponenziale e per 16 pesci è già di diversi secondi.
Vorrei calcolare la risposta per schede di dimensioni 32 * 32 e con 100 target mobili.
Domanda
Qual è un algoritmo efficiente (idealmente in Javascript) per calcolare il numero minimo di passaggi per raccogliere tutti i target?
Quello che ho provato
Il mio attuale approccio si basa sulla memorizzazione ma è molto lento e non so se genererà sempre la soluzione migliore.
Risolvo il sottoproblema di "qual è il numero minimo di passaggi per raccogliere un determinato insieme di obiettivi e finire in un determinato obiettivo?".
Il sottoproblema viene risolto ricorsivamente esaminando ogni scelta per il target precedente da visitare. Presumo che sia sempre ottimale raccogliere il precedente sottoinsieme di bersagli il più rapidamente possibile e poi spostarsi dalla posizione in cui sei finito al bersaglio corrente il più rapidamente possibile (anche se non so se questo sia un presupposto valido).
Ciò si traduce in n * 2 ^ n stati da calcolare che crescono molto rapidamente.
Il codice corrente è mostrato di seguito:
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;
}
Quello che ho considerato
Alcune opzioni che mi sono chiesto sono:
Memorizzazione nella cache dei risultati intermedi. Il calcolo della distanza ripete molte simulazioni ei risultati intermedi potrebbero essere memorizzati nella cache.
Tuttavia, non credo che ciò impedirebbe che abbia una complessità esponenziale.Un algoritmo di ricerca A * sebbene non sia chiaro quale sarebbe un'euristica ammissibile appropriata e quanto sarebbe efficace nella pratica.
Investigare buoni algoritmi per il problema del venditore ambulante e vedere se si applicano a questo problema.
Cercare di dimostrare che il problema è NP-difficile e quindi irragionevole cercare una risposta ottimale.