배경
이 그림은 문제를 보여줍니다.
빨간색 원을 제어 할 수 있습니다. 대상은 파란색 삼각형입니다. 검은 색 화살표는 표적이 이동할 방향을 나타냅니다.
최소한의 단계로 모든 목표를 수집하고 싶습니다.
회전 할 때마다 왼쪽 / 오른쪽 / 위 또는 아래로 한 단계 씩 이동해야합니다.
매 턴마다 목표물은 보드에 표시된 지시에 따라 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가 어렵 기 때문에 이에 대한 최적의 답을 찾는 것이 부당하다는 것을 증명하려고합니다.