मैं 100 बढ़ते लक्ष्य के बीच सबसे छोटा रास्ता कैसे खोज सकता हूं? (लाइव डेमो शामिल)


89

पृष्ठभूमि

यह चित्र समस्या का चित्रण करता है: square_grid_with_arrows_giving_directions

मैं लाल घेरे को नियंत्रित कर सकता हूं। लक्ष्य नीले त्रिकोण हैं। काले तीर उस दिशा को इंगित करते हैं जो लक्ष्य को स्थानांतरित करेगा।

मैं सभी लक्ष्यों को न्यूनतम चरणों में एकत्रित करना चाहता हूं।

प्रत्येक मोड़ पर मुझे 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;
}

जो मैंने माना है

कुछ विकल्प जिनके बारे में मैंने सोचा है वे हैं:

  1. इंटरमीडिएट के परिणामों की कैशिंग। दूरी की गणना बहुत अधिक दोहराती है और मध्यवर्ती परिणाम कैश्ड हो सकते हैं।
    हालाँकि, मुझे नहीं लगता कि इससे घातीय जटिलता होना बंद हो जाएगी।

  2. एक ए * सर्च एल्गोरिथ्म हालांकि यह मेरे लिए स्पष्ट नहीं है कि एक उपयुक्त स्वीकार्य अनुमान क्या होगा और यह व्यवहार में कितना प्रभावी होगा।

  3. यात्रा विक्रेता समस्या के लिए अच्छे एल्गोरिदम की जांच करना और देखें कि क्या वे इस समस्या पर लागू होते हैं।

  4. यह साबित करने की कोशिश की जा रही है कि समस्या एनपी-कठिन है और इसलिए अनुचित है कि इसके लिए एक इष्टतम जवाब की मांग की जाए।


1
मैं # 4 के लिए और बाद में # 3 के लिए जाना होगा: बड़े पर्याप्त बोर्डों के साथ, यह टीएसपी की अच्छी तरह से नकल करता है।
जॉन ड्वोरक

2
जहां तक ​​मैं जानता हूं, टीएसपी यूपीलिडीन मीट्रिक के साथ-साथ मैनहट्टन मीट्रिक (स्क्वायर ग्रिड) के साथ एनपी-हार्ड है।
जॉन ड्वोरक

1
यदि आप इसे सरल पेड़-खोज द्वारा करते हैं, तो हाँ, यह घातीय होगा। हालाँकि, यदि आप प्रत्येक चरण में एक सभ्य हेयुरिस्टिक पा सकते हैं, तो यह वास्तव में इष्टतम नहीं हो सकता है, लेकिन यह बहुत अच्छा हो सकता है। मछलियों के वर्तमान सेट को देखते हुए, एक संभव अनुमानी होगा, जिसे सबसे अधिक तेज़ी से पहुँचा जा सकता है? एक सेकेंडरी हेयुरिस्टिक हो सकता है, जो 2 मछली मैं सबसे जल्दी से पहुंच सकता हूं?
माइक डनलैवी

2
@MikeDunlavey जो लालची टीएसपी एल्गोरिथ्म के अनुरूप होगा, और यह व्यवहार में बहुत अच्छी तरह से काम करता है। निकटतम मछली के लिए जाना एक अच्छा विचार लगता है
जॉन ड्वोरक

1
सामग्री और संरचना दोनों के लिए मैंने सबसे अच्छे प्रश्नों में से एक को देखा है।
20:13

जवाबों:


24

क्या आपने साहित्य खोजा है? मुझे ये कागज मिले जो आपकी समस्या का विश्लेषण करने के लिए लगता है:

अद्यतन 1:

उपरोक्त दो पेपर यूक्लिडियन मीट्रिक के लिए रैखिक आंदोलन पर ध्यान केंद्रित करते हैं।


धन्यवाद - मैंने उन कागजों को नहीं देखा था लेकिन वे बहुत प्रासंगिक लगते हैं। मैं देखूंगा कि क्या मैं अपने मामले में काम करने के लिए आनुवंशिक एल्गोरिथ्म को अनुकूलित कर सकता हूं और इसकी तुलना जानवर बल के दृष्टिकोण से कर सकता हूं।
पीटर डी रिवाज़

13

लालची विधि

टिप्पणियों में सुझाए गए एक दृष्टिकोण को सबसे पहले निकटतम लक्ष्य पर जाना है।

मैंने डेमो का एक संस्करण रखा है जिसमें इस लालची विधि के माध्यम से गणना की गई लागत शामिल है

कोड है:

function greedyMethod(start_x,start_y) {
  var still_to_visit = (1<<pts.length)-1;
  var pt=[start_x,start_y];
  var s=0;
  while (still_to_visit) {
    var besti=-1;
    var bestc=0;
    for(i=0;i<pts.length;i++) {
      var bit = 1<<i;
      if (still_to_visit&bit) {
        c = fastest_route(pt,getPt(i,s));
        if (besti<0 || c<bestc) {
          besti = i;
          bestc = c;
        }
      }
    }
    s+=c;
    still_to_visit -= 1<<besti;
    pt=getPt(besti,s);
  }
  return s;
}

10 लक्ष्यों के लिए यह लगभग दो बार इष्टतम दूरी है, लेकिन कभी-कभी बहुत अधिक (जैसे * 4) और कभी-कभी इष्टतम को भी मारता है।

यह दृष्टिकोण बहुत कुशल है इसलिए मैं उत्तर को बेहतर बनाने के लिए कुछ चक्रों को वहन कर सकता हूं।

आगे मैं चींटी कॉलोनी विधियों का उपयोग करने पर विचार कर रहा हूं ताकि वे समाधान स्थान का प्रभावी ढंग से पता लगा सकें।

चींटी कॉलोनी विधि

एक इस समस्या के लिए एंट कॉलोनी विधि उल्लेखनीय रूप से अच्छी तरह से काम करती है। इस उत्तर में लिंक अब लालची और चींटी कॉलोनी पद्धति का उपयोग करते हुए परिणामों की तुलना करता है।

विचार यह है कि चींटियाँ फेरोमोन के वर्तमान स्तर के आधार पर संभावित रूप से अपना मार्ग चुनती हैं। हर 10 परीक्षणों के बाद, हम सबसे छोटे निशान के साथ अतिरिक्त फेरोमोन जमा करते हैं जो उन्होंने पाया।

function antMethod(start_x,start_y) {
  // First establish a baseline based on greedy
  var L = greedyMethod(start_x,start_y);
  var n = pts.length;
  var m = 10; // number of ants
  var numrepeats = 100;
  var alpha = 0.1;
  var q = 0.9;
  var t0 = 1/(n*L);

  pheromone=new Array(n+1); // entry n used for starting position
  for(i=0;i<=n;i++) {
    pheromone[i] = new Array(n);
    for(j=0;j<n;j++)
      pheromone[i][j] = t0; 
  }

  h = new Array(n);
  overallBest=10000000;
  for(repeat=0;repeat<numrepeats;repeat++) {
    for(ant=0;ant<m;ant++) {
      route = new Array(n);
      var still_to_visit = (1<<n)-1;
      var pt=[start_x,start_y];
      var s=0;
      var last=n;
      var step=0;
      while (still_to_visit) {
        var besti=-1;
        var bestc=0;
        var totalh=0;
        for(i=0;i<pts.length;i++) {
          var bit = 1<<i;
          if (still_to_visit&bit) {
            c = pheromone[last][i]/(1+fastest_route(pt,getPt(i,s)));
            h[i] = c;
            totalh += h[i];
            if (besti<0 || c>bestc) {
              besti = i;
              bestc = c;
            }
          }
        }
        if (Math.random()>0.9) {
          thresh = totalh*Math.random();
          for(i=0;i<pts.length;i++) {
            var bit = 1<<i;
            if (still_to_visit&bit) {
              thresh -= h[i];
              if (thresh<0) {
                besti=i;
                break;
              }
            }
          }
        }
        s += fastest_route(pt,getPt(besti,s));
        still_to_visit -= 1<<besti;
        pt=getPt(besti,s);
        route[step]=besti;
        step++;
        pheromone[last][besti] = (1-alpha) * pheromone[last][besti] + alpha*t0;
        last = besti;
      }
      if (ant==0 || s<bestantscore) {
        bestroute=route;
        bestantscore = s;
      }
    }
    last = n;
    var d = 1/(1+bestantscore);
    for(i=0;i<n;i++) {
      var besti = bestroute[i];
      pheromone[last][besti] = (1-alpha) * pheromone[last][besti] + alpha*d;
      last = besti;
    }
    overallBest = Math.min(overallBest,bestantscore);
  }
  return overallBest;
}

परिणाम

10 चींटियों के 100 दोहराव का उपयोग करने वाली यह चींटी कॉलोनी विधि अभी भी बहुत तेज़ है (संपूर्ण खोज के लिए 3700ms की तुलना में 16 लक्ष्यों के लिए 37ms) और बहुत सटीक लगती है।

नीचे दी गई तालिका 16 लक्ष्यों का उपयोग करते हुए 10 परीक्षणों के लिए परिणाम दिखाती है:

   Greedy   Ant     Optimal
   46       29      29
   91       38      37
  103       30      30
   86       29      29
   75       26      22
  182       38      36
  120       31      28
  106       38      30
   93       30      30
  129       39      38

चींटी विधि लालची की तुलना में काफी बेहतर लगती है और अक्सर इष्टतम के बहुत करीब होती है।


अच्छा लगा। आपके पास अभी तक संपूर्ण खोज से इष्टतम परिणाम नहीं हो सकते हैं (या संभवतः इसकी इंट्रेक्टबिलिटी के कारण कभी नहीं!), लेकिन यह देखना दिलचस्प होगा कि समान आकार के लक्ष्य के साथ बोर्ड आकार (32x32) के साथ चींटी कॉलोनी कैसे होती है।
टाइमसीज

8

समस्या को सामान्यीकृत ट्रैवलिंग सेल्समैन समस्या के रूप में दर्शाया जा सकता है, और फिर एक पारंपरिक ट्रैवलिंग सेल्समैन समस्या में परिवर्तित किया जा सकता है। यह एक अच्छी तरह से अध्ययन की समस्या है। यह संभव है कि ओपी की समस्या का सबसे कुशल समाधान टीएसपी के समाधान से अधिक कुशल नहीं है, लेकिन किसी भी तरह से निश्चित नहीं है (मैं शायद ओपी की समस्या संरचना के कुछ पहलुओं का लाभ उठाने में विफल रहा हूं जो कि जल्दी समाधान के लिए अनुमति देगा। , जैसे इसकी चक्रीय प्रकृति)। किसी भी तरह से, यह एक अच्छा प्रारंभिक बिंदु है।

से सी दोपहर और J.Bean, सामान्यीकृत यात्रा विक्रेता की समस्या का एक कुशल परिवर्तन :

सामान्यीकृत यात्रा विक्रेता की समस्या (GTSP) चयन और अनुक्रम के निर्णयों को शामिल समस्याओं के लिए एक उपयोगी मॉडल है। समस्या के असममित संस्करण को नोड्स एन के साथ एक निर्देशित ग्राफ पर परिभाषित किया गया है, जो आर्क ए और एक समान आर्क लागत सी को जोड़ता है। नोड्स को m अनन्य रूप से अनन्य और संपूर्ण नोड्स में प्रीग्रुप किया गया है। कनेक्टिंग आर्क्स को केवल अलग-अलग सेट से संबंधित नोड्स के बीच परिभाषित किया गया है, अर्थात, कोई इंट्रसेट आर्क नहीं हैं। प्रत्येक परिभाषित चाप में एक समान गैर-नकारात्मक लागत होती है। जीटीएसपी को न्यूनतम लागत एम-आर्क चक्र खोजने की समस्या के रूप में कहा जा सकता है जिसमें प्रत्येक नोड से एक नोड शामिल है

ओपी की समस्या के लिए:

  • प्रत्येक सदस्य Nएक विशेष समय में एक विशेष मछली का स्थान है। इस के रूप में प्रतिनिधित्व करते हैं (x, y, t), जहां (x, y)एक ग्रिड समन्वय है, और tवह समय है जिसमें मछली इस समन्वय पर होगी। ओपी के उदाहरण में सबसे बाईं मछली के लिए, इनमें से पहले कुछ (1-आधारित) हैं:(3, 9, 1), (4, 9, 2), (5, 9, 3) जैसे मछली सही चलती है।
  • N के किसी भी सदस्य के fish(n_i)लिए नोड द्वारा दर्शाई गई मछली की आईडी वापस कर दें । एन के किसी भी दो सदस्यों के manhattan(n_i, n_j)लिए हम दो नोड्स के बीच मैनहट्टन दूरी के लिए गणना कर सकते हैं, औरtime(n_i, n_j ) नोड्स के बीच की ऑफसेट समय के लिए।
  • असंतुष्ट सबसेट मी की संख्या मछली की संख्या के बराबर है। डिसऑइंट सब्मिट S_iमें केवल वे नोड्स शामिल होंगे जिनके लिएfish(n) == i
  • यदि दो नोड्स के लिए iऔर j fish(n_i) != fish(n_j)फिर बीच में एक चाप है iऔरj
  • नोड I और नोड j के बीच की लागत time(n_i, n_j)या अपरिभाषित है , time(n_i, n_j) < distance(n_i, n_j)( यदि मछली के वहां पहुंचने से पहले स्थान पर नहीं पहुंचा जा सकता है, शायद इसलिए कि यह समय में पीछे की ओर है)। इस बाद के प्रकार के आर्क को हटाया जा सकता है।
  • एक अतिरिक्त नोड को सभी अन्य नोड्स के लिए आर्क्स और लागत के साथ खिलाड़ी के स्थान का प्रतिनिधित्व करने के लिए जोड़ना होगा।

इस समस्या को हल करने के बाद प्रत्येक नोड सबसेट (यानी प्रत्येक मछली एक बार प्राप्त की जाती है) पर न्यूनतम लागत (यानी सभी मछलियों को प्राप्त करने के लिए न्यूनतम समय) के लिए एक यात्रा का परिणाम होगा।

कागज यह वर्णन करने के लिए आगे बढ़ता है कि कैसे उपरोक्त सूत्रीकरण एक पारंपरिक ट्रैवलिंग सेल्समैन समस्या में परिवर्तित हो सकता है और बाद में मौजूदा तकनीकों से हल या अनुमानित हो सकता है। मैंने विवरण के माध्यम से नहीं पढ़ा है, लेकिन एक और पेपर जो इसे इस तरह से करता है कि यह कुशल होने की घोषणा करता है

जटिलता के साथ स्पष्ट मुद्दे हैं। विशेष रूप से, नोड स्पेस अनंत है! यह केवल एक निश्चित समय क्षितिज तक नोड उत्पन्न करके समाप्त किया जा सकता है। यदि tनोड्स उत्पन्न करने के लिए टाइमस्टेप fकी संख्या है और मछली की संख्या है तो नोड स्पेस का आकार होगा t * f। समय के साथ एक नोड jसबसे अधिक (f - 1) * (t - j)आउटगोइंग आर्क पर होगा (क्योंकि यह समय में या अपने सबसेट पर वापस नहीं जा सकता)। आर्क्स की कुल संख्या के क्रम में होगीt^2 * f^2 । चाप की संरचना को संभवत: ख़त्म किया जा सकता है, इस तथ्य का लाभ उठाने के लिए कि मछली के मार्ग अंततः चक्रीय हैं। मछली अपने चक्र की लंबाई के सबसे कम आम हर एक बार उनके विन्यास को दोहराएगी ताकि शायद इस तथ्य का उपयोग किया जा सके।

मुझे टीएसपी के बारे में यह जानने के लिए पर्याप्त नहीं है कि यह संभव है या नहीं, और मुझे नहीं लगता कि इसका मतलब यह है कि पोस्ट की गई समस्या आवश्यक रूप से एनपी-हार्ड है ... लेकिन यह एक इष्टतम या बाध्य समाधान खोजने के लिए एक दृष्टिकोण है। ।


धन्यवाद, यह मेरे लिए नया है और बहुत दिलचस्प है। मुझे लगता है कि मुझे इस परिवर्तन का उपयोग क्रिस्टोफ़ाइड्स एल्गोरिथ्म के संयोजन में करने में सक्षम होना चाहिए ताकि यह इष्टतम रूप से 3/2 के सन्निकटन कारक के भीतर एक समाधान ढूंढ सके। अगर मुझे यह काम करने के लिए मिलता है तो मैं उत्पादित मार्गों को डेमो पेज पर जोड़ दूंगा।
पीटर डी रिवाज

आह, मुझे लगता है कि इसमें मेरी योजना के साथ एक समस्या है, हालांकि मेरी मूल समस्या एक पूर्ण ग्राफ़ है जो मीट्रिक पर एक उपयुक्त असमानता को संतुष्ट करती है, परिवर्तन का वर्णन अपूर्ण ग्राफ़ में होता है और इसलिए क्रिस्टोफ़ाइड एल्गोरिथ्म अब लागू नहीं होता है। दिलचस्प परिप्रेक्ष्य के लिए वैसे भी धन्यवाद।
पीटर डी रिवाज़

हां मैं उस त्रिभुज असमानता का उल्लेख करना नहीं भूलता। हालाँकि, यह एक अच्छा जंपिंग पॉइंट है, जो ह्यूरिस्टिक सॉल्यूशंस और अधिक सामान्य अनुमानों के लिए है।
टिम्सीज़

1

मुझे लगता है कि एक और दृष्टिकोण होगा:

  • लक्ष्यों के पथ की गणना करें - भविष्य कहनेवाला।
  • Voronoi आरेखों का उपयोग करने से

उद्धरण विकिपीडिया:

गणित में, एक वोरोनोई आरेख अंतरिक्ष के कई क्षेत्रों में विभाजित करने का एक तरीका है। अंकों का एक सेट (जिसे बीज, साइट, या जनरेटर कहा जाता है) पहले से निर्दिष्ट है और प्रत्येक बीज के लिए एक समान क्षेत्र होगा जिसमें किसी भी अन्य की तुलना में उस बीज के करीब सभी बिंदु शामिल होंगे।

इसलिए, आप एक लक्ष्य चुनते हैं, कुछ चरणों के लिए इसका अनुसरण करते हैं और एक बीज बिंदु निर्धारित करते हैं। अन्य सभी लक्ष्यों के साथ भी ऐसा करें और आपको एक वोरोनी आरेख मिलता है। आप किस क्षेत्र में हैं, इस पर निर्भर करते हुए, आप इसके आधार पर आगे बढ़ते हैं। वियोला, आपको पहली मछली मिली। अब इस चरण को तब तक दोहराएं जब तक कि आप उन सभी को नहीं जीत लेते।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.