पृष्ठभूमि
यह चित्र समस्या का चित्रण करता है:
मैं लाल घेरे को नियंत्रित कर सकता हूं। लक्ष्य नीले त्रिकोण हैं। काले तीर उस दिशा को इंगित करते हैं जो लक्ष्य को स्थानांतरित करेगा।
मैं सभी लक्ष्यों को न्यूनतम चरणों में एकत्रित करना चाहता हूं।
प्रत्येक मोड़ पर मुझे 1 कदम या तो बाएं / दाएं / ऊपर या नीचे जाना चाहिए।
प्रत्येक मोड़ लक्ष्य को बोर्ड पर दिखाए गए निर्देशों के अनुसार 1 कदम भी बढ़ाएगा।
डेमो
मैंने Google appengine पर यहाँ समस्या का एक खेलने योग्य डेमो रखा है ।
मुझे बहुत दिलचस्पी होगी अगर कोई भी लक्ष्य स्कोर को हरा सकता है क्योंकि इससे पता चलता है कि मेरा वर्तमान एल्गोरिथ्म सबऑप्टिमल है। (यदि आप इसे प्रबंधित करते हैं तो एक बधाई संदेश मुद्रित किया जाना चाहिए!)
संकट
मेरा वर्तमान एल्गोरिथ्म लक्ष्य की संख्या के साथ वास्तव में बुरी तरह से तराजू है। समय तेजी से बढ़ता है और 16 मछलियों के लिए यह पहले से ही कई सेकंड है।
मैं 32 * 32 के बोर्ड आकार के लिए और 100 चलती लक्ष्यों के साथ उत्तर की गणना करना चाहूंगा।
सवाल
सभी लक्ष्यों को एकत्र करने के लिए न्यूनतम संख्या में कदमों की गणना के लिए एक कुशल एल्गोरिदम (आदर्श रूप से जावास्क्रिप्ट में) क्या है?
मैंने क्या कोशिश की है
मेरा वर्तमान दृष्टिकोण स्मरण पर आधारित है, लेकिन यह बहुत धीमा है और मुझे नहीं पता कि यह हमेशा सबसे अच्छा समाधान उत्पन्न करेगा या नहीं।
मैं "किसी दिए गए लक्ष्य को प्राप्त करने और किसी विशेष लक्ष्य पर समाप्त होने के लिए कदमों की न्यूनतम संख्या क्या है?"
पिछले लक्ष्य के लिए प्रत्येक विकल्प की जांच करके उपप्रोफ़्म को पुनरावर्ती रूप से हल किया जाता है। मुझे लगता है कि यह लक्ष्यों के पिछले सबसेट को जितनी जल्दी हो सके इकट्ठा करने के लिए हमेशा इष्टतम है और फिर उस स्थिति से आगे बढ़ें जिसे आपने वर्तमान लक्ष्य तक जितनी जल्दी हो सके (हालांकि मुझे नहीं पता कि यह एक मान्य धारणा है)।
इसके परिणामस्वरूप 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;
}
जो मैंने माना है
कुछ विकल्प जिनके बारे में मैंने सोचा है वे हैं:
इंटरमीडिएट के परिणामों की कैशिंग। दूरी की गणना बहुत अधिक दोहराती है और मध्यवर्ती परिणाम कैश्ड हो सकते हैं।
हालाँकि, मुझे नहीं लगता कि इससे घातीय जटिलता होना बंद हो जाएगी।एक ए * सर्च एल्गोरिथ्म हालांकि यह मेरे लिए स्पष्ट नहीं है कि एक उपयुक्त स्वीकार्य अनुमान क्या होगा और यह व्यवहार में कितना प्रभावी होगा।
यात्रा विक्रेता समस्या के लिए अच्छे एल्गोरिदम की जांच करना और देखें कि क्या वे इस समस्या पर लागू होते हैं।
यह साबित करने की कोशिश की जा रही है कि समस्या एनपी-कठिन है और इसलिए अनुचित है कि इसके लिए एक इष्टतम जवाब की मांग की जाए।