Lý lịch
Hình ảnh này minh họa vấn đề:
Tôi có thể kiểm soát vòng tròn màu đỏ. Mục tiêu là các hình tam giác màu xanh lam. Các mũi tên màu đen cho biết hướng mà các mục tiêu sẽ di chuyển.
Tôi muốn thu thập tất cả các mục tiêu theo số bước tối thiểu.
Mỗi lượt tôi phải di chuyển 1 bước sang trái / phải / lên hoặc xuống.
Mỗi lượt đi các mục tiêu cũng sẽ di chuyển 1 bước theo chỉ dẫn trên bảng.
Bản giới thiệu
Tôi đã đưa ra một bản demo có thể chơi được về vấn đề ở đây trên Google appengine .
Tôi sẽ rất quan tâm nếu ai đó có thể vượt qua điểm số mục tiêu vì điều này sẽ cho thấy rằng thuật toán hiện tại của tôi là chưa tối ưu. (Một thông báo chúc mừng sẽ được in nếu bạn quản lý được điều này!)
Vấn đề
Thuật toán hiện tại của tôi có quy mô thực sự tồi tệ với số lượng mục tiêu. Thời gian tăng lên theo cấp số nhân và đối với 16 con cá là vài giây.
Tôi muốn tính toán câu trả lời cho kích thước bảng là 32 * 32 và với 100 mục tiêu di động.
Câu hỏi
Thuật toán hiệu quả (lý tưởng là trong Javascript) để tính toán số bước tối thiểu để thu thập tất cả các mục tiêu là gì?
Những gì tôi đã thử
Cách tiếp cận hiện tại của tôi dựa trên sự ghi nhớ nhưng nó rất chậm và tôi không biết liệu nó có luôn tạo ra giải pháp tốt nhất hay không.
Tôi giải quyết vấn đề con "số bước tối thiểu để thu thập một tập hợp mục tiêu nhất định và kết thúc ở một mục tiêu cụ thể là bao nhiêu?".
Bài toán con được giải một cách đệ quy bằng cách kiểm tra từng lựa chọn cho mục tiêu trước đó đã được truy cập. Tôi giả định rằng luôn luôn là tối ưu để thu thập tập hợp con mục tiêu trước đó càng nhanh càng tốt và sau đó di chuyển từ vị trí bạn đã kết thúc đến mục tiêu hiện tại càng nhanh càng tốt (mặc dù tôi không biết liệu đây có phải là một giả định hợp lệ hay không).
Điều này dẫn đến n * 2 ^ n trạng thái được tính toán phát triển rất nhanh.
Mã hiện tại được hiển thị bên dưới:
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;
}
Những gì tôi đã xem xét
Một số tùy chọn mà tôi băn khoăn là:
Lưu trữ các kết quả trung gian. Việc tính toán khoảng cách lặp lại rất nhiều mô phỏng và kết quả trung gian có thể được lưu vào bộ nhớ đệm.
Tuy nhiên, tôi không nghĩ rằng điều này sẽ ngăn nó có độ phức tạp theo cấp số nhân.Một thuật toán tìm kiếm A * mặc dù đối với tôi không rõ ràng là một kinh nghiệm tìm kiếm có thể chấp nhận thích hợp sẽ là gì và điều này sẽ hiệu quả như thế nào trong thực tế.
Điều tra các thuật toán tốt cho bài toán nhân viên bán hàng lưu động và xem chúng có áp dụng cho bài toán này không.
Cố gắng chứng minh rằng vấn đề là NP-khó và do đó không hợp lý khi tìm kiếm một câu trả lời tối ưu cho nó.