Передумови
Цей малюнок ілюструє проблему:
Я можу керувати червоним колом. Мішенями є сині трикутники. Чорні стрілки вказують напрямок руху цілей.
Я хочу зібрати всі цілі за мінімальну кількість кроків.
На кожному повороті я повинен рухатись на 1 крок вліво / вправо / вгору або вниз.
Кожен поворот цілі також рухатиметься на 1 крок відповідно до вказівок, показаних на дошці.
Демо
Я опублікував демонстраційну демонстраційну проблему тут на Google Appendine .
Мені було б дуже цікаво, якщо хтось зможе перевершити цільовий бал, оскільки це покаже, що мій поточний алгоритм неоптимальний. (Якщо вам це вдається, слід надрукувати привітальне повідомлення!)
Проблема
Мій поточний алгоритм дуже погано масштабується за кількістю цілей. Час зростає в геометричній прогресії, і для 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-важка і, отже, нерозумно шукати оптимальну відповідь на неї.