พื้นหลัง
ภาพนี้แสดงให้เห็นถึงปัญหา:
ฉันควบคุมวงกลมสีแดงได้ เป้าหมายคือสามเหลี่ยมสีน้ำเงิน ลูกศรสีดำระบุทิศทางที่เป้าหมายจะเคลื่อนที่
ฉันต้องการรวบรวมเป้าหมายทั้งหมดในจำนวนขั้นต่ำ
แต่ละเทิร์นฉันต้องเลื่อน 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 * แม้ว่าจะไม่ชัดเจนสำหรับฉันว่าฮิวริสติกที่ยอมรับได้ที่เหมาะสมจะเป็นอย่างไรและจะมีประสิทธิภาพเพียงใดในทางปฏิบัติ
ตรวจสอบอัลกอริทึมที่ดีสำหรับปัญหาพนักงานขายที่เดินทางและดูว่ามีผลกับปัญหานี้หรือไม่
พยายามที่จะพิสูจน์ว่าปัญหานั้นยากมากและด้วยเหตุนี้จึงไม่มีเหตุผลที่จะแสวงหาคำตอบที่ดีที่สุดสำหรับปัญหานี้