Contexte
Cette image illustre le problème:
Je peux contrôler le cercle rouge. Les cibles sont les triangles bleus. Les flèches noires indiquent la direction dans laquelle les cibles se déplaceront.
Je souhaite collecter toutes les cibles en un minimum d'étapes.
À chaque tour, je dois faire un pas vers la gauche / droite / vers le haut ou vers le bas.
À chaque tour, les cibles se déplaceront également d'un pas selon les directions indiquées sur le tableau.
Démo
J'ai mis en place une démo jouable du problème ici sur Google appengine .
Je serais très intéressé si quelqu'un pouvait battre le score cible car cela montrerait que mon algorithme actuel est sous-optimal. (Un message de félicitations devrait être imprimé si vous gérez cela!)
Problème
Mon algorithme actuel évolue très mal avec le nombre de cibles. Le temps augmente de façon exponentielle et pour 16 poissons, il est déjà de plusieurs secondes.
Je voudrais calculer la réponse pour des tailles de carte de 32 * 32 et avec 100 cibles mobiles.
Question
Qu'est-ce qu'un algorithme efficace (idéalement en Javascript) pour calculer le nombre minimum d'étapes pour collecter toutes les cibles?
Ce que j'ai essayé
Mon approche actuelle est basée sur la mémoisation mais elle est très lente et je ne sais pas si elle générera toujours la meilleure solution.
Je résous le sous-problème de "quel est le nombre minimum d'étapes pour collecter un ensemble donné de cibles et aboutir à une cible particulière?".
Le sous-problème est résolu de manière récursive en examinant chaque choix de la cible précédente à avoir visité. Je suppose qu'il est toujours optimal de collecter le sous-ensemble précédent de cibles aussi rapidement que possible, puis de passer de la position où vous vous êtes retrouvé à la cible actuelle le plus rapidement possible (bien que je ne sache pas si c'est une hypothèse valable).
Il en résulte n * 2 ^ n états à calculer qui croît très rapidement.
Le code actuel est indiqué ci-dessous:
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;
}
Ce que j'ai considéré
Certaines options sur lesquelles je me suis interrogé sont:
Mise en cache des résultats intermédiaires. Le calcul de la distance répète de nombreuses simulations et les résultats intermédiaires peuvent être mis en cache.
Cependant, je ne pense pas que cela l'empêcherait d'avoir une complexité exponentielle.Un algorithme de recherche A * bien que je ne sache pas ce que serait une heuristique admissible appropriée et quelle serait son efficacité dans la pratique.
Enquêter sur de bons algorithmes pour le problème du voyageur de commerce et voir s'ils s'appliquent à ce problème.
Essayer de prouver que le problème est NP-difficile et donc déraisonnable de chercher une réponse optimale pour cela.