背景
此图说明了问题:
我可以控制红色圆圈。目标是蓝色三角形。黑色箭头指示目标将移动的方向。
我想以最少的步骤收集所有目标。
每转一圈,我必须向左/向右/向上或向下移动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难题,因此不合理地寻求最佳答案。