शतरंज की बिसात पर सबसे छोटा रास्ता


95

मैं एक आगामी प्रोग्रामिंग प्रतियोगिता के लिए अभ्यास कर रहा हूं और मैंने एक सवाल पर ठोकर खाई है कि मैं पूरी तरह से हतप्रभ हूं। हालाँकि, मुझे लगता है कि यह एक अवधारणा है जिसे मुझे अपनी उंगलियों को पार करने के बजाय अब सीखना चाहिए कि यह कभी नहीं आती है।

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

मैंने कभी भी छोटी-छोटी बातों को नहीं बताया, और मुझे यह भी नहीं पता कि कहाँ से शुरू किया जाए। इससे निपटने के लिए मैं क्या तर्क देता हूं?

पुनश्च यदि यह किसी भी प्रासंगिकता का है, तो वे चाहते हैं कि आप नाइट के सामान्य चाल को पूरक कर सकें, जिससे यह बनते हुए वर्ग के चार कोनों पर जा सके (संभवतः) आठ चालें एक नाइट बना सकती हैं, जिसे देखते हुए वर्ग का केंद्र है शूरवीर का स्थान।


क्या आप पीएस को स्पष्ट कर सकते हैं? आपका मतलब है, अगर एक नाइट ई 4 पर है, तो यह C2, C6, G2 और G6 में जा सकता है?
स्टीव टोज़ा

हां, इसके अलावा यह सामान्य चाल है।
काइल ह्यूजेस

1
यहाँ समस्या का कुछ गणितीय विश्लेषण है: math.stackexchange.com/questions/104700/…
ग्रीम पाइल

जवाबों:


28

आपके पास यहां एक ग्राफ़ है, जहां सभी उपलब्ध चालें जुड़ी हुई हैं (मान = 1), और अनुपलब्ध चालें काट दी जाती हैं (मान = 0), विरल मैट्रिक्स इस तरह होगा:

(a1,b3)=1,
(a1,c2)=1,
  .....

और एक ग्राफ में दो बिंदुओं का सबसे छोटा रास्ता http://en.wikipedia.org/wiki/Dijkstra_algorithm का उपयोग करके पाया जा सकता है

विकिपीडिया-पृष्ठ से छद्म कोड:

function Dijkstra(Graph, source):
   for each vertex v in Graph:           // Initializations
       dist[v] := infinity               // Unknown distance function from source to v
       previous[v] := undefined          // Previous node in optimal path from source
   dist[source] := 0                     // Distance from source to source
   Q := the set of all nodes in Graph
   // All nodes in the graph are unoptimized - thus are in Q
   while Q is not empty:                 // The main loop
       u := vertex in Q with smallest dist[]
       if dist[u] = infinity:
          break                         // all remaining vertices are inaccessible from source
       remove u from Q
       for each neighbor v of u:         // where v has not yet been removed from Q.
           alt := dist[u] + dist_between(u, v) 
           if alt < dist[v]:             // Relax (u,v,a)
               dist[v] := alt
               previous[v] := u
   return dist[]

संपादित करें:

  1. मोरन के रूप में, http://en.wikipedia.org/wiki/A*_algorithm का उपयोग करके तेज किया जा सकता है।
  2. सबसे तेज़ तरीका, सभी दूरियों की पूर्व-गणना करना और इसे 8x8 पूर्ण मैट्रिक्स में सहेजना है। ठीक है, मैं उस धोखा को कहूंगा, और काम केवल इसलिए होगा क्योंकि समस्या छोटी है। लेकिन कभी-कभी प्रतियोगिताओं की जांच होगी कि आपका कार्यक्रम कितनी तेजी से चलता है।
  3. मुख्य बिंदु यह है कि यदि आप एक प्रोग्रामिंग प्रतियोगिता की तैयारी कर रहे हैं, तो आपको डायजेस्ट्रा सहित आम एल्गोरिदम को जानना होगा। एक अच्छा प्रारंभिक बिंदु Introduction to Algorithmsआईएसबीएन 0-262-03384-4 पढ़ रहा है। या आप विकिपीडिया, http://en.wikipedia.org/wiki/List_of_al एल्गोरिदम की कोशिश कर सकते हैं

नीचे मुस्तफा के समाधान की तुलना में यह जटिल लगता है।
lpapp

अनुपलब्ध चाल से आपका क्या अभिप्राय है? एक नाइट किसी भी वर्ग तक पहुँच सकता है !?
सदाबहार

51

EDIT: सिमोन का जवाब देखें , जहां उन्होंने यहां प्रस्तुत सूत्र को ठीक किया।

वास्तव में एक O (1) सूत्र है

यह एक ऐसी छवि है जिसे मैंने इसे कल्पना करने के लिए बनाया है (वर्गों को एक नाइट पर पहुंच सकते हैं एन वें चाल को उसी रंग से चित्रित किया जाता है)। नाइट की चाल

क्या आप यहां पैटर्न देख सकते हैं?

यद्यपि हम पैटर्न को देख सकते हैं, यह फ़ंक्शन को खोजने के लिए वास्तव में कठिन है f( x , y )जो वर्ग से वर्ग ( 0 , 0 )तक जाने के लिए आवश्यक चाल की संख्या लौटाता है( x , y )

लेकिन यहां वह सूत्र है जो कब काम करता है 0 <= y <= x

int f( int x , int y )
{
    int delta = x - y;

    if( y > delta )
        return 2 * ( ( y - delta ) / 3 ) + delta;
    else
        return delta - 2 * ( ( delta - y ) / 4 );
}

नोट: यह सवाल एसएसीओ 2007 दिवस 1 पर पूछा गया था
और समाधान यहां हैं


8
कोई भी मौका आप यह बता सकते हैं कि आपने उस फॉर्मूले पर कैसे काम किया?
kybernetikos

3
क्या यह कोड काम करता है? यदि एक नाइट स्थिति (0,0) पर है और मैं इसे बिंदु (1,0) पर ले जाना चाहता हूं। यह 0 <= y <= x को संतुष्ट करता है। डेल्टा = 1-0 = 1. y डेल्टा (0 <1) से बड़ा नहीं है। इसका मतलब है कि मैं दूसरे मामले के लिए जा रहा हूं। डेल्टा - 2 * ((डेल्टा - y) / 4) = 1-2 ((1-0) / 4) = 1-1 / 2 = 1। है ना व्हाय I नाइट मूव (0,0) से (1,0) एक मूव में। प्रश्न क्या यह अल्गोरिटम काम करता है? या मैं क्या गलत कर रहा हूँ?
सिंपलऐप

3
ऐसा लगता है कि यह केवल प्रत्यक्ष संभव पदों के लिए काम करता है। लेकिन अगर उपयोगकर्ता (2,2) प्रदान करता है तो यह 0 देता है और यदि उपयोगकर्ता (4,4) प्रदान करता है तो यह 2 रिटर्न देता है जो गलत है।
युनस

6
यह होना चाहिए 2 * floor((y - delta) / 3) + deltaऔर delta - 2 * floor((delta - y) / 4)। यह इस प्रतियोगिता पृष्ठ से आधिकारिक समाधान है, लेकिन यह गलत है। यह पहला समीकरण (से if) गलत उत्तर देता है। शतरंज की बिसात पर [-1000..1000] x [-1000..1000], जो 2001x2001 बड़ा (लेकिन तार्किक रूप से असीमित) है, दिए गए जवाब में 4,004,001 क्षेत्रों में से 2,669,329 की गिनती सही (66.66%) है। किसी को भी किसी भी छोरों के बिना काम कर समाधान पता है?
रोबो रोबोक

2
मैं मानता हूं कि यह समाधान काम नहीं करता है। अन्य जवाब देखें जैसे कि एक काम करने वाले ओ (1) समाधान के लिए stackoverflow.com/a/26888893/4288232
टिमएससी

45

यहां एक सही O (1) समाधान है, लेकिन इस मामले के लिए जहां शूरवीर केवल शतरंज के शूरवीर की तरह चलता है, और अनंत शतरंज बोर्ड पर:

https://jsfiddle.net/graemian/5qgvr1ba/11/

इसे खोजने की कुंजी बोर्ड को ड्रा करते समय उभरने वाले पैटर्न को नोटिस करना है। नीचे दिए गए चित्र में, वर्ग में संख्या उस वर्ग तक पहुंचने के लिए आवश्यक न्यूनतम चाल है (आप इसे खोजने के लिए चौड़ाई-प्रथम खोज का उपयोग कर सकते हैं):

पैटर्न्स

क्योंकि समाधान कुल्हाड़ियों और विकर्णों में सममित है, मैंने केवल x> = 0 और y> = x केस खींचा है।

नीचे-बाएँ ब्लॉक प्रारंभिक स्थिति है और ब्लॉक में संख्या उन ब्लॉकों तक पहुंचने के लिए न्यूनतम संख्या में चालों का प्रतिनिधित्व करती है।

नोटिस करने के लिए 3 पैटर्न हैं:

  • 4 के बढ़ते नीले ऊर्ध्वाधर समूह
  • "प्राथमिक" लाल विकर्ण (वे बैकस्लैश की तरह ऊपर-नीचे से दाएं-बाएं चलते हैं)
  • "द्वितीयक" हरी विकर्ण (लाल के रूप में एक ही अभिविन्यास)

(यह सुनिश्चित करें कि आप विकर्णों के दोनों सेटों को शीर्ष-बाएँ से नीचे-दाएँ के रूप में देखते हैं। उनकी निरंतर चाल-गणना है। नीचे-बाएँ शीर्ष-दाएँ विकर्ण बहुत अधिक जटिल हैं।)

आप प्रत्येक के लिए सूत्र प्राप्त कर सकते हैं। पीले रंग के ब्लॉक विशेष मामले हैं। तो समाधान बन जाता है:

function getMoveCountO1(x, y) {

    var newXY = simplifyBySymmetry(x, y);

    x = newXY.x;
    y = newXY.y;

    var specialMoveCount = getSpecialCaseMoveCount(x ,y);

    if (specialMoveCount !== undefined)
        return specialMoveCount;

    else if (isVerticalCase(x, y))
        return getVerticalCaseMoveCount(x ,y);

    else if (isPrimaryDiagonalCase(x, y))
        return getPrimaryDiagonalCaseMoveCount(x ,y);

    else if (isSecondaryDiagonalCase(x, y))
        return getSecondaryDiagonalCaseMoveCount(x ,y);

}

ऊर्ध्वाधर समूहों में सबसे कठिन होने के साथ:

function isVerticalCase(x, y) {

    return y >= 2 * x;

}

function getVerticalCaseMoveCount(x, y) {

    var normalizedHeight = getNormalizedHeightForVerticalGroupCase(x, y);

    var groupIndex = Math.floor( normalizedHeight / 4);

    var groupStartMoveCount = groupIndex * 2 + x;

    return groupStartMoveCount + getIndexInVerticalGroup(x, y);

}

function getIndexInVerticalGroup(x, y) {

    return getNormalizedHeightForVerticalGroupCase(x, y) % 4;

}

function getYOffsetForVerticalGroupCase(x) {

    return x * 2;

}

function getNormalizedHeightForVerticalGroupCase(x, y) {

    return y - getYOffsetForVerticalGroupCase(x);

}

अन्य मामलों के लिए पहेली देखें।

शायद वहाँ सरल या अधिक सुंदर पैटर्न मैं याद कर रहे हैं? यदि हां, तो मैं उन्हें देखना पसंद करूंगा। विशेष रूप से, मैं नीले ऊर्ध्वाधर मामलों में कुछ विकर्ण पैटर्न देखता हूं, लेकिन मैंने उन्हें खोजा नहीं है। बावजूद, यह समाधान अभी भी हे (1) बाधा को संतुष्ट करता है।


यह (शाब्दिक) कोने के मामलों को संभालने के लिए प्रतीत नहीं होता है। यदि बोर्ड (a1) पर "0" निचला निचला वर्ग है, तो आप दो चालों में निकटतम "2" स्थान (b2) पर नहीं पहुंच सकते। क्योंकि ऐसा करने के लिए आपकी पहली चाल (a3) ​​के बाईं ओर मौजूद गैर-मौजूद जगह के लिए होगी।
जॉन हस्कल

ठीक है, मैंने अनंत शतरंज बोर्ड धारणा को शामिल करने के लिए अपना जवाब बदल दिया
ग्रीम पेले

@JonatasWalker कृपया समझाएं, मुझे (8,0) से (0,0) तक जाने में कोई समस्या नहीं दिख रही है। यह 4 चाल लेता है?
ग्रीम पाइल

क्षमा करें @GraemePyle, मेरी गलती, मेरी टिप्पणी को हटा दें।
जोनाटस वाकर

2
hi @GraemePyle - मैं आपसे सहमत हूं कि यह सबसे अच्छा समग्र प्रोग्रामिंग दृष्टिकोण है। जिस तरह से महान आरेख!
फेटी

22

बहुत दिलचस्प समस्या है जिसका मुझे हाल ही में सामना करना पड़ा था। कुछ समाधानों को देखने के बाद मुझे SACO 2007 दिवस 1 समाधानO(1) time and space complexity पर दिए गए विश्लेषणात्मक सूत्र ( ) को पुनर्प्राप्त करने की कोशिश की गई ।

सबसे पहले मैं बहुत अच्छे दृश्य के लिए ग्रीम पाइल की सराहना करना चाहता हूं जिसने मुझे सूत्र को ठीक करने में मदद की।

किसी कारण के लिए (शायद सरलीकरण या सुंदरता या सिर्फ एक गलती के लिए) वे ऑपरेटर minusमें साइन ले गए floor, परिणामस्वरूप उन्हें गलत फॉर्मूला मिला है floor(-a) != -floor(a) for any a

यहाँ सही विश्लेषणात्मक सूत्र है:

var delta = x-y;
if (y > delta) {
    return delta - 2*Math.floor((delta-y)/3);
} else {
    return delta - 2*Math.floor((delta-y)/4);
}

सूत्र (एक्स, वाई) जोड़े (एक्सिस और विकर्ण समरूपता को लागू करने के बाद) (1,0) और (2,2) कोने के मामलों के लिए काम करता है, जो निम्न स्निपेट में पैटर्न और हार्डकोड के लिए संतुष्ट नहीं हैं:

function distance(x,y){
     // axes symmetry 
     x = Math.abs(x);
     y = Math.abs(y);
     // diagonal symmetry 
     if (x < y) {
        t = x;x = y; y = t;
     }
     // 2 corner cases
     if(x==1 && y == 0){
        return 3;
     }
     if(x==2 && y == 2){
        return 4;
     }
    
    // main formula
    var delta = x-y;
		if(y>delta){
  		return delta - 2*Math.floor((delta-y)/3);
  	}
  	else{
  		return delta - 2*Math.floor((delta-y)/4);
  	}
}


$body = $("body");
var html = "";
for (var y = 20; y >= 0; y--){
	html += '<tr>';
	for (var x = 0; x <= 20; x++){
  	html += '<td style="width:20px; border: 1px solid #cecece" id="'+x+'_'+y+'">'+distance(x,y)+'</td>';
  }
  html += '</tr>';
}

html = '<table>'+html+'</table>';
$body.append(html);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>

नोट: jQuery केवल चित्रण के लिए उपयोग किया जाता है, कोड देखें distanceफ़ंक्शन के लिए।


2
@OlegAbrazhaev "दूरी" फ़ंक्शन एक विश्लेषणात्मक फ़ंक्शन है और ओ (1) समय में दिए गए (x, y) स्थिति के लिए चरणों की संख्या की गणना कर सकता है। मूल रूप से इस सूत्र में हम बोर्ड पर निर्भर नहीं होते हैं (मुझे लगता है कि "अनंत बोर्ड" से आपका मतलब उस संपत्ति से है), इसलिए यह काम करेगा।
सिमोन

2
@ साइमन कृपया कोई मुख्य सूत्र समझा सकता है? मुझे सरल शब्दों में इसे समझाने में सक्षम होना मुश्किल है
MarBVI

1
@MarBVI अगर हम y = x लाइन के पास हैं तो हम x = y को हर कदम पर y = x रेखा के पास रहकर घटा सकते हैं। अगर हम y = 0 लाइन के पास हैं तो हम y = 0 लाइन के पास रहकर हर चाल में x 2 घटा सकते हैं। यही कारण है कि हमारे पास 2 मामले हैं, विशेष रूप से विशेष पंक्ति के पास कहने से मेरा मतलब है: 1. y = x रेखा से मेरा मतलब है कि अनुभाग y = x और y = x / 2 लाइनों (y> x / 2) द्वारा प्रतिबंधित है )। 2. y = 0 लाइन के पास मेरा मतलब है कि y = 0 और y = x / 2 लाइनों (y <x / 2) द्वारा प्रतिबंधित अनुभाग। उपर्युक्त सभी को ध्यान में रखते हुए और यदि हम Math.floor को हटाते हैं और मुख्य सूत्र को सरल करते हैं तो हमें निम्नलिखित सूत्र मिलेंगे: if (y> x / 2) तो {return (x + y) / 3} और {रिटर्न x / 2}
simon

1
@ साइमन महान, जो इसे और अधिक स्पष्ट करता है ... आपके समय के लिए ty :)
MarBVI

1
बस मामले में, BAPC2017 प्रतियोगिता में एक अनंत बोर्ड पर नाइट के मैराथन नाम का एक प्रश्न था कि यह सूत्र इसे पूरी तरह से हल करता है। 2017.bapc.eu/files/preliminaries_problems.pdf
अमीर-

19

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

सादगी के लिए, आइए शतरंज बोर्ड को (x, y) विमान के रूप में वर्णित करें। लक्ष्य केवल उम्मीदवार चरणों (+ -1, + -2), (+ -2, + -1), और (+ -2) का उपयोग करके (x0, y0) (X1, y1) से सबसे छोटा रास्ता खोजने का है। , + -2), जैसा कि प्रश्न के PS में वर्णित है

यहां नया अवलोकन है: कोनों (x-4, y-4), (x-4, y + 4), (x + 4, y-4), (x + 4, y + 4) के साथ एक वर्ग खींचें । इस सेट (इसे S4 कहते हैं) में 32 बिंदु हैं। इन 32 बिंदुओं (x, y) में से किसी भी सबसे छोटे मार्ग के लिए ठीक दो चालों की आवश्यकता होती है

सेट S3 (इसी तरह परिभाषित) (x, y) में 24 बिंदुओं में से किसी एक से सबसे छोटा रास्ता कम से कम दो चालों की आवश्यकता है

इसलिए, अगर | X1-x0। एस 4। और बाद की समस्या को सीधे पुनरावृत्ति के साथ जल्दी से हल किया जा सकता है।

आज्ञा दें एन = अधिकतम (! X1-x0 | |; y1-y0 |)। यदि N> = 4 है, तो सबसे छोटा रास्ता (x0, y0) से (X1, y1) में छत (N / 2) चरण हैं।


1
क्या यह सिर्फ मुझे है जो इस उत्तर के बारे में उलझन में है? "कोनों (x-4, y-4), (x-4, y + 4), (x + 4, y-4), (x + 4, y + 4) के साथ एक वर्ग खींचें। यह सेट (कॉल) यह S4) में 32 अंक हैं "। नहीं, ऐसा नहीं है, इसमें 81 है क्योंकि यह 9x9 वर्ग है? इसके अलावा, "N = अधिकतम! (X1-x0 | |; y1-y0 |) | यदि N> = 4, तो सबसे छोटा रास्ता (x0, y0) से (X1, y1) में छत (N / 2) है | कदम।" यह सच नहीं है, उदाहरण के लिए x0 = 0, y0 = 0, X1 = 4, y1 = 4 लें, सबसे छोटा रास्ता 4 है, 2 नहीं जैसा कि सूत्र बताते हैं।
satoshi

1
(1) सेट केवल वर्ग की सीमा पर बिंदुओं को संदर्भित करता है। जिसमें 32 अंक / स्थान हैं। (2) जब आप पूरक चालों के बारे में पोस्टर के पीएस को ध्यान में रखते हैं (मूल पोस्ट में टिप्पणियों को भी देखते हैं), न्यूनतम संख्या में चालें दो हो जाती हैं।
स्टीव टोज़ा

धन्यवाद, जो अब समझ में आता है :)
satoshi

क्या होगा अगर एक बोर्ड अनंत है? इस मामले में केवल
बीएफएस

@SteveTjoa क्षमा करें, मैं समझ नहीं पा रहा हूं कि आपने (+ -2, + -2) का उल्लेख क्यों किया, क्योंकि यह एक नाइट के लिए असंभव है
पावेल बेली

12

मुस्तफा सेरदार danlı द्वारा [ https://stackoverflow.com/a/8778592/4288232 ] के ऊपर ओ (1) उत्तर वास्तव में काम नहीं कर रहा है। (चेक (1,1) या (3,2) या (4,4), स्पष्ट किनारे के मामलों (1,0) या (2,2) के लिए अलग।

नीचे एक बहुत बदसूरत समाधान (अजगर) है, जो काम करता है (जोड़ा "परीक्षण" के साथ):

def solve(x,y):
        x = abs(x)
        y = abs(y)
        if y > x:
            temp=y
            y=x
            x=temp  
        if (x==2 and y==2):
            return 4
        if (x==1 and y==0):
            return 3

    if(y == 0 or float(y) / float(x) <= 0.5):
        xClass = x % 4
        if (xClass == 0):
            initX = x/2
        elif(xClass == 1):
            initX = 1 + (x/2)
        elif(xClass == 2):
            initX = 1 + (x/2)
        else:
            initX = 1 + ((x+1)/2)

        if (xClass > 1):
            return initX - (y%2)
        else:
            return initX + (y%2)
    else:
        diagonal = x - ((x-y)/2)
        if((x-y)%2 == 0):
            if (diagonal % 3 == 0):
                return (diagonal/3)*2
            if (diagonal % 3 == 1):
                return ((diagonal/3)*2)+2
            else:
                return ((diagonal/3)*2)+2
        else:
            return ((diagonal/3)*2)+1


def test():
    real=[
    [0,3,2,3,2,3,4,5,4,5,6,7,6,7],
    [3,2,1,2,3,4,3,4,5,6,5,6,7,8],
    [2,1,4,3,2,3,4,5,4,5,6,7,6,7],
    [3,2,3,2,3,4,3,4,5,6,5,6,7,8],
    [2,3,2,3,4,3,4,5,4,5,6,7,6,7],
    [3,4,3,4,3,4,5,4,5,6,5,6,7,8],
    [4,3,4,3,4,5,4,5,6,5,6,7,6,7],
    [5,4,5,4,5,4,5,6,5,6,7,6,7,8],
    [4,5,4,5,4,5,6,5,6,7,6,7,8,7],
    [5,6,5,6,5,6,5,6,7,6,7,8,7,8],
    [6,5,6,5,6,5,6,7,6,7,8,7,8,9],
    [7,6,7,6,7,6,7,6,7,8,7,8,9,8]]

    for x in range(12):
        for y in range(12):
            res = solve(x,y)
            if res!= real[x][y]:
                print (x, y), "failed, and returned", res, "rather than", real[x][y]
            else:
               print (x, y), "worked. Cool!"

test()

10
वास्तव में एसओ पर काम करता है aboveया belowनहीं के रूप में जवाब का जिक्र ।
पेट्र पेलर

1
यहाँ अजगर 2/3 में मेरा संस्करण है। मैंने हल फ़ंक्शन को सरल बनाने की कोशिश की है लेकिन यह आसान नहीं है! gist.github.com/TimSC/8b9a80033f3a22a708a4b9741931c591
TimSC

9

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


1
+!, इस विशिष्ट समस्या के लिए BFS पर्याप्त है।
तियांसुओ

3
BFS पर्याप्त हो सकता है, लेकिन एक सादा BST कई प्रश्नों के लिए उड़ा देगा - आपको कैश करना होगा कि आपने कौन से वर्गों का दौरा किया है। और फिर बीएफएस को दिक्क्स्ट्रा के एल्गोरिथ्म की तरह थोड़ा सा दिखना शुरू हो जाता है ...
चार्ल्स स्टीवर्ट

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

मुझे लगता है कि हम अपनी अंतिम नाइट स्थिति को स्टोर करके बस कर सकते हैं?
नितीश उप्रेती

7

पायथन में पहले सिद्धांतों से समाधान

मैंने पहली बार एक कोडलिटी टेस्ट में इस समस्या का सामना किया। उन्होंने मुझे इसे हल करने के लिए 30 मिनट का समय दिया - इस परिणाम को पाने के लिए मुझे इससे अधिक समय लगा! समस्या यह थी: केवल कानूनी नाइट के कदमों का उपयोग करके, 0,0 से x, y तक जाने के लिए नाइट के लिए कितनी चालें चलती हैं। x और y अधिक-या-कम अनबाउंड थे (इसलिए हम यहां एक सरल 8x8 शतरंजबोर्ड के बारे में बात नहीं कर रहे हैं)।

वे एक ओ (1) समाधान चाहते थे। मैं एक समाधान चाहता था जहां कार्यक्रम स्पष्ट रूप से समस्या को हल कर रहा था (यानी मैं ग्रीम के पैटर्न की तुलना में अधिक स्पष्ट रूप से कुछ सही चाहता था - पैटर्न जहां आप नहीं देख रहे हैं वहां टूटने की आदत है), और मैं वास्तव में एक पर भरोसा नहीं करना चाहता था असंगठित सूत्र, जैसा कि मुस्तफा के समाधान में है

तो, यहाँ मेरा समाधान है, इसके लायक क्या है। प्रारंभ करें, जैसा कि दूसरों के पास है, समाधान को देखकर कुल्हाड़ियों और विकर्णों के बारे में सममित है, इसलिए हमें केवल 0> = y> = x के लिए हल करने की आवश्यकता है। स्पष्टीकरण की सादगी के लिए (और कोड) मैं समस्या को उलटने जा रहा हूं: नाइट x, y से शुरू होता है, और 0,0 के लिए लक्ष्य होता है।

मान लीजिए कि हम समस्या को मूल के आसपास के क्षेत्र में सिकोड़ते हैं। हमें वास्तव में नियत समय में 'विंची' से क्या मिलेगा, लेकिन अभी के लिए, आइए नीचे दिए गए कुछ समाधानों को एक चेसशीट में लिखें (नीचे बाईं ओर मूल):

2 1 4 3
3 2 1 2
0 3 2 3

तो, ग्रिड पर x, y दिए गए हैं, हम मूल में चालों की संख्या को पढ़ सकते हैं।

अगर हमने ग्रिड के बाहर शुरू कर दिया है, तो हमें अपने तरीके से वापस काम करना होगा। हम 'मिडलाइन' का परिचय देते हैं, जो कि y = x / 2 द्वारा दर्शाई गई रेखा है। उस लाइन पर x, y पर कोई भी शूरवीर 8 बजे चाल की एक श्रृंखला का उपयोग करके वापस धोखा देती है (जो है: (-2, -1) चाल)। यदि x, y मिडलाइन के ऊपर स्थित है, तो हमें 8 बजे और 7 बजे की चाल के उत्तराधिकार की आवश्यकता होगी, और यदि यह मिडलाइन के नीचे स्थित है, तो हमें 8 बजे और 10 बजे के उत्तराधिकार की आवश्यकता होगी 'घड़ी चलती है। यहां ध्यान देने योग्य दो बातें:

  • ये क्रम काफी कम पथ हैं। (मुझे यह साबित करने के लिए चाहते हैं, या यह स्पष्ट है?)
  • हम केवल इस तरह की चालों की संख्या की परवाह करते हैं। हम किसी भी क्रम में चालों का मिश्रण और मिलान कर सकते हैं।

तो, चलो ऊपर-मिडलाइन चाल को देखते हैं। हम जो दावा कर रहे हैं, वह है:

  • (dx; डाई) = (2,1; 1,2) (n8; n7) (मैट्रिक्स संकेतन, गणित के बिना टाइपसेटिंग - कॉलम वेक्टर (dx; डाई) स्तंभ वेक्टर द्वारा गुणा किए गए वर्ग मैट्रिक्स के बराबर है (n8; n7;) 8 बजे की संख्या और 7 बजे की चाल की संख्या), और इसी तरह;

  • (dx; डाई) = (2,2; 1, -1) (n8; n10)

मैं दावा कर रहा हूं कि dx, डाई लगभग (x, y) होगा, इसलिए (x-dx, y-dy) मूल के आसपास के क्षेत्र में होगा (जो कुछ भी 'आसपास' निकला)।

कोड में दो पंक्तियाँ जो इन पदों की गणना करती हैं, इनका समाधान है, लेकिन वे कुछ उपयोगी गुणों के लिए चुने गए हैं:

  • उपरोक्त-मिडलाइन फॉर्मूला (0, y) (0,0), (1,1) या (2,2) में से किसी एक पर जाता है।
  • नीचे-मिडलाइन फॉर्मूला (0, y) (0,0), (1,0), (2,0), या (1,1) में से एक पर चलता है।

(क्या आप इनके प्रमाण चाहेंगे?) इसलिए, नाइट की दूरी n7, n8, n10 और cheatsheet [x-dx, y-dy] का योग होगा, और हमारी cheatsheet इसके लिए कम हो जाती है:

. . 4
. 2 .
0 3 2

अब, यह कहानी का अंत नहीं है। नीचे पंक्ति पर 3 को देखो। हम इस तक पहुँच सकते हैं एक ही तरीके हैं:

  • हमने वहां शुरुआत की, या
  • 8 बजे और 10 बजे की चाल से हम वहां चले गए। लेकिन यदि अंतिम चाल 8 बजे थी (जो कि इसका हकदार है, क्योंकि हम किसी भी क्रम में अपनी चाल चल सकते हैं), तो हमें (3,1) से गुजरना होगा, जिसकी दूरी वास्तव में 2 है (जैसा कि आप कर सकते हैं) मूल धोखा से देखें)। तो हमें जो करना चाहिए, वह एक 8 बजे की चाल है, कुल मिलाकर दो चालें बचती हैं।

शीर्ष दाईं ओर 4 के साथ एक समान अनुकूलन होना चाहिए। वहां से शुरू करने के अलावा, उस तक पहुंचने का एकमात्र तरीका (4,3) से 8 बजे की चाल है। यह चीटशीट पर नहीं है, लेकिन अगर यह वहां था, तो इसकी दूरी 3 होगी, क्योंकि हम इसके बजाय 7 बजे (3,1) कर सकते थे, जिसकी दूरी केवल 2 है। इसलिए, हमें एक को वापस ट्रैक करना चाहिए 8-बजे चलती है, और फिर एक 7-आगे बढ़ते हैं।

इसलिए, हमें एक और नंबर को धोखा देने के लिए जोड़ना होगा:

. . 4
. 2 . 2
0 3 2

(ध्यान दें: (0,1) और (0,2) से बैक-ट्रैकिंग ऑप्टिमाइज़ेशन का एक पूरा लोड है, लेकिन चूंकि सॉल्वर हमें कभी नहीं ले जाएगा, हमें उनके बारे में चिंता करने की ज़रूरत नहीं है।)

तो, यहाँ, इसका मूल्यांकन करने के लिए कुछ पायथन कोड है:

def knightDistance (x, y):
    # normalise the coordinates
    x, y = abs(x), abs(y)
    if (x<y): x, y = y, x
    # now 0 <= y <= x

    # n8 means (-2,-1) (8 o'clock), n7 means (-1,-2) (7 o'clock), n10 means (-2,+1) (10 o'clock)
    if (x>2*y):
        # we're below the midline.  Using 8- & 10-o'clock moves
        n7, n8, n10 = 0,  (x + 2*y)//4,  (x - 2*y + 1)//4
    else:
        # we're above the midline.  Using 7- and 8-o'clock moves
        n7, n8, n10 = (2*y - x)//3, (2*x - y)//3,  0
    x -= 2*n8 + n7 + 2*n10
    y -= n8 + 2*n7 - n10
    # now 0<=x<=2, and y <= x.  Also (x,y) != (2,1)

    # Try to optimise the paths.
    if (x, y)==(1, 0): # hit the  3.  Did we need to?
        if (n8>0): # could have passed through the 2 at 3,1.  Back-up
            x, y = 3, 1; n8-=1;
    if (x, y)==(2, 2): # hit the 4.  Did we need to?
        if (n8>0): # could have passed through a 3 at 4,3.  Back-up, and take 7 o'clock to 2 at 3,1
            x, y = 3, 1; n8-=1; n7+=1

    # Almost there.  Now look up the final leg
    cheatsheet = [[0, 3, 2], [2, None, 2], [4]]
    return n7 + n8 + n10 + cheatsheet [y][x-y]

संयोग से, यदि आप एक वास्तविक मार्ग जानना चाहते हैं, तो यह एल्गोरिथ्म यह भी प्रदान करता है: यह केवल n7 7-olock चालों का एक उत्तराधिकार है, इसके बाद (या के साथ interspersed) n8 8-olock चाल, n10 10- ऑक्सलॉक मूव्स, और जो भी डांस चीटशीट द्वारा डिक्टेट किया गया है (जो कि खुद ही चीटिंगशीट में हो सकता है)।

अब: यह कैसे साबित किया जाए। केवल सही उत्तरों की तालिका के साथ इन परिणामों की तुलना करना पर्याप्त नहीं है, क्योंकि समस्या स्वयं अनबाउंड है। लेकिन हम यह कह सकते हैं कि, यदि एक वर्ग s की नाइट की दूरी d है, तो यदि {m} s से कानूनी चाल का सेट है, तो नाइट की दूरी (s + m) या तो d-1 या d + 1 होनी चाहिए सभी के लिए एम। (क्या आपको इसके प्रमाण की आवश्यकता है?) इसके अलावा, कम से कम एक ऐसा वर्ग होना चाहिए जिसकी दूरी d-1 है, जब तक कि एस मूल न हो। इसलिए, हम इस गुण को प्रत्येक वर्ग के लिए धारण करके शुद्धता साबित कर सकते हैं। इस प्रकार:

def validate (n):

    def isSquareReasonable (x, y):
        d, downhills = knightDistance (x, y), 0
        moves = [(1, 2), (2, 1), (2, -1), (1, -2), (-1, -2), (-2, -1), (-2, 1), (-1,  2)]
        for dx, dy in moves:
            dd = knightDistance (x+dx,  y+dy)
            if (dd == d+1): pass
            elif (dd== d-1): downhills += 1
            else: return False;
        return (downhills>0) or (d==0)

    for x in range (0,  n+1):
        for y in range (0,  n+1):
            if not isSquareReasonable (x,  y): raise RuntimeError ("Validation failed")

वैकल्पिक रूप से, हम डाउनहिल से उत्पत्ति तक के मार्ग का पीछा करते हुए किसी एक वर्ग s की शुद्धता को साबित कर सकते हैं। सबसे पहले, उपर्युक्त के रूप में तर्कशीलता की जांच करें, फिर किसी भी s + m का चयन करें, जो दूरी (s + m) == d-1 है। जब तक हम मूल तक नहीं पहुंचते तब तक दोहराएं।

Howzat?


2
/*
This program takes two sets of cordinates on a 8*8 chessboard, representing the
starting and ending points of a knight's path.
The problem is to print the cordinates that the knight traverses in between, following
the shortest path it can take.
Normally this program is to be implemented using the Djikstra's algorithm(using graphs)
but can also be implemented using the array method.
NOTE:Between 2 points there may be more than one shortest path. This program prints
only one of them.
*/

#include<stdio.h>

#include<stdlib.h>

#include<conio.h>

int m1=0,m2=0;

/*
This array contains three columns and 37 rows:
The rows signify the possible coordinate differences.
The columns 1 and 2 contains the possible permutations of the row and column difference 
between two positions on a chess board;
The column 3 contains the minimum number of steps involved in traversing the knight's 
path with the given permutation*/

int arr[37][3]={{0,0,0},{0,1,3},{0,2,2},{0,3,3},{0,4,2},{0,5,3},{0,6,4},{0,7,5},    {1,1,2},{1,2,1},{1,3,2},{1,4,3},{1,5,4},{1,6,3},{1,7,4},{2,2,4},{2,3,3},{2,4,2},
            {2,5,3},{2,6,3},{2,7,5},{3,3,2},{3,4,3},{3,5,4},{3,6,3},{3,7,4},{4,4,4},{4,5,3},{4,6,4},{4,7,5},{5,5,4},{5,6,5},{5,7,4},{6,6,5},{6,7,5},{7,7,6}};

void printMoves(int,int,int,int,int,int);
void futrLegalMove(int,int,int,int);
main()
{
  printf("KNIGHT'S SHORTEST PATH ON A 8*8 CHESSBOARD :\n");
  printf("------------------------------------------");
  printf("\nThe chessboard may be treated as a 8*8 array here i.e. the (1,1) ");
  printf("\non chessboard is to be referred as (0,0) here and same for (8,8) ");
  printf("\nwhich is to be referred as (7,7) and likewise.\n");
  int ix,iy,fx,fy;
  printf("\nEnter the initial position of the knight :\n");
  scanf("%d%d",&ix,&iy);
  printf("\nEnter the final position to be reached :\n");
  scanf("%d%d",&fx,&fy);
  int px=ix,py=iy;
  int temp;
  int tx,ty;
  printf("\nThe Knight's shortest path is given by :\n\n");
  printf("(%d, %d)",ix,iy);
  futrLegalMove(px,py,m1,m2);
  printMoves(px,py,fx,fy,m1,m2);
   getch();
} 

/*
  This method checkSteps() checks the minimum number of steps involved from current
  position(a & b) to final position(c & d) by looking up in the array arr[][].
*/

int checkSteps(int a,int b,int c,int d)
{  
    int xdiff, ydiff;
    int i, j;
    if(c>a)
        xdiff=c-a;
    else
        xdiff=a-c;
    if(d>b)
        ydiff=d-b;
    else
        ydiff=b-d;
    for(i=0;i<37;i++)
        {
            if(((xdiff==arr[i][0])&&(ydiff==arr[i][1])) || ((xdiff==arr[i][1])&& (ydiff==arr[i] [0])))
            {
                j=arr[i][2];break;
            }
        }

        return j;
}   

/*
This method printMoves() prints all the moves involved.
*/

void printMoves(int px,int py, int fx, int fy,int a,int b)
{    
 int temp;
 int tx,ty;
 int t1,t2;
  while(!((px==fx) && (py==fy)))
  {   
      printf(" --> ");
      temp=checkSteps(px+a,py+b,fx,fy);
      tx=px+a;
      ty=py+b;
      if(!(a==2 && b==1))
      {if((checkSteps(px+2,py+1,fx,fy)<temp) && checkMove(px+2,py+1))
      {temp=checkSteps(px+2,py+1,fx,fy);
       tx=px+2;ty=py+1;}}
      if(!(a==2 && b==-1))
      {if((checkSteps(px+2,py-1,fx,fy)<temp) && checkMove(px+2,py-1))
      {temp=checkSteps(px+2,py-1,fx,fy);
       tx=px+2;ty=py-1;}}
      if(!(a==-2 && b==1))
      {if((checkSteps(px-2,py+1,fx,fy)<temp) && checkMove(px-2,py+1))
      {temp=checkSteps(px-2,py+1,fx,fy);
       tx=px-2;ty=py+1;}}
      if(!(a==-2 && b==-1))
      {if((checkSteps(px-2,py-1,fx,fy)<temp) && checkMove(px-2,py-1))
      {temp=checkSteps(px-2,py-1,fx,fy);
       tx=px-2;ty=py-1;}}
      if(!(a==1 && b==2))
      {if((checkSteps(px+1,py+2,fx,fy)<temp) && checkMove(px+1,py+2))
      {temp=checkSteps(px+1,py+2,fx,fy);
       tx=px+1;ty=py+2;}}
      if(!(a==1 && b==-2))
      {if((checkSteps(px+1,py-2,fx,fy)<temp) && checkMove(px+1,py-2))
      {temp=checkSteps(px+1,py-2,fx,fy);
       tx=px+1;ty=py-2;}}
      if(!(a==-1 && b==2))
      {if((checkSteps(px-1,py+2,fx,fy)<temp) && checkMove(px-1,py+2))
      {temp=checkSteps(px-1,py+2,fx,fy);
       tx=px-1;ty=py+2;}}
      if(!(a==-1 && b==-2))
      {if((checkSteps(px-1,py-2,fx,fy)<temp) && checkMove(px-1,py-2))
      {temp=checkSteps(px-1,py-2,fx,fy);
       tx=px-1;ty=py-2;}}
       t1=tx-px;//the step taken in the current move in the x direction.
       t2=ty-py;//" " " " " " " " " " " " " " " " " " " " " y " " " " ".
       px=tx;
       py=ty;
       printf("(%d, %d)",px,py);
       futrLegalMove(px,py,t1,t2);
       a=m1;
       b=m2;
   }

} 

/*
The method checkMove() checks whether the move in consideration is beyond the scope of
board or not.
*/   

int checkMove(int a, int b)
{
    if(a>7 || b>7 || a<0 || b<0)
        return 0;
    else
        return 1;
}

/*Out of the 8 possible moves, this function futrLegalMove() sets the valid move by
  applying the following constraints
      1. The next move should not be beyond the scope of the board.
      2. The next move should not be the exact opposite of the previous move.
  The 1st constraint is checked by sending all possible moves to the checkMove() 
  method;
  The 2nd constraint is checked by passing as parameters(i.e. a and b) the steps of the 
  previous move and checking whether or not it is the exact opposite of the current move.
*/

void futrLegalMove(int px,int py,int a,int b)
{
     if(checkMove(px+2,py+1) && (a!=-2 && b!=-1))
         m1=2,m2=1;
     else
     {
         if(checkMove(px+2,py-1)&& (a!=-2 && b!=1))
             m1=2,m2=-1;
     else
     {
         if(checkMove(px-2,py+1)&& (a!=2 && b!=-1))
              m1=-2,m2=1;
     else
     {
         if(checkMove(px-2,py-1)&& (a!=2 && b!=1))
               m1=-2,m2=-1;
     else
     {
         if(checkMove(px+1,py+2)&& (b!=-2 && a!=-1))
               m2=2,m1=1;
     else
     {
         if(checkMove(px+1,py-2)&& (a!=-1 && b!=2))
               m2=-2,m1=1;
     else
     {
         if(checkMove(px-1,py+2)&& (a!=1 && b!=-2))
               m2=2,m1=-1;
     else
     {
         if(checkMove(px-1,py-2)&& (a!=1 && b!=2))
               m2=-2,m1=-1;
     }}}}}}}
}

//End of Program.

मैंने अभी तक रेखांकन का अध्ययन नहीं किया है..तो इसे केवल सरणियों के माध्यम से लागू करने की समस्या के बावजूद, मैं इसके अलावा कोई समाधान नहीं निकाल सका। मैंने पदों को रैंक और फाइलों (सामान्य शतरंज अंकन) के रूप में नहीं, बल्कि सरणी सूचकांकों के रूप में माना। FYI करें, यह केवल 8 *, शतरंज की बिसात के लिए है। किसी भी सुधार सलाह का हमेशा स्वागत किया जाता है।

* टिप्पणियाँ तर्क की आपकी समझ के लिए पर्याप्त होनी चाहिए। हालाँकि, आप हमेशा पूछ सकते हैं।

* DEV-C ++ 4.9.9.2 संकलक (रक्तपात सॉफ्टवेयर) पर जाँच की गई।


2

मुझे लगता है कि इससे आपको भी मदद मिल सकती है।

NumWays(x,y)=1+min(NumWays(x+-2,y-+1),NumWays(x+-1,y+-2)); 

और समाधान प्राप्त करने के लिए डायनामिक प्रोग्रामिंग का उपयोग करना।

पुनश्च: यह थोड़े ग्राफ के नोड्स और किनारों को घोषित करने की परेशानी उठाए बिना बीएफएस का उपयोग करता है।


1

यहाँ पर्ल में लागू इस विशेष समस्या के लिए एक समाधान है। यह सबसे छोटे रास्तों में से एक दिखाएगा - कुछ मामलों में एक से अधिक हो सकता है।

मैंने ऊपर वर्णित किसी भी एल्गोरिदम का उपयोग नहीं किया - लेकिन इसे अन्य समाधानों से तुलना करना अच्छा होगा।

#!/usr/local/bin/perl -w

use strict;

my $from = [0,0];
my $to   = [7,7];

my $f_from = flat($from);
my $f_to   = flat($to);

my $max_x = 7;
my $max_y = 7;
my @moves = ([-1,2],[1,2],[2,1],[2,-1],[1,-2],[-1,-2],[-2,-1],[-2,1]);
my %squares = ();
my $i = 0;
my $min = -1;

my @s = ( $from );

while ( @s ) {

   my @n = ();
   $i++;

   foreach my $s ( @s ) {
       unless ( $squares{ flat($s) } ) {
            my @m = moves( $s );
            push @n, @m;
            $squares{ flat($s) } = { i=>$i, n=>{ map {flat($_)=>1} @m }, };

            $min = $i if $squares{ flat($s) }->{n}->{$f_to};
       }
   }

   last if $min > -1;
   @s = @n;
}

show_path( $f_to, $min );

sub show_path {
    my ($s,$i) = @_;

    return if $s eq $f_from;

    print "$i => $f_to\n" if $i == $min;

    foreach my $k ( keys %squares ) {
       if ( $squares{$k}->{i} == $i && $squares{$k}->{n}->{$s} ) {
            $i--;
            print "$i => $k\n";
            show_path( $k, $i );
            last;
       }
    }
}

sub flat { "$_[0]->[0],$_[0]->[1]" }

sub moves {
    my $c = shift;
    my @s = ();

    foreach my $m ( @moves ) {
       my $x = $c->[0] + $m->[0];
       my $y = $c->[1] + $m->[1];

       if ( $x >= 0 && $x <=$max_x && $y >=0 && $y <=$max_y) {
           push @s, [$x, $y];
       }
    }
    return @s;
}

__END__

1
public class Horse {

    private int[][] board;
    private int[] xer = { 2, 1, -1, -2, -2, -1, 1, 2 };
    private int[] yer = { 1, 2, 2, 1, -1, -2, -2, -1 };
    private final static int A_BIG_NUMBER = 10000;
    private final static int UPPER_BOUND = 64;


    public Horse() {
        board =  new int[8][8];
    }

    private int solution(int x, int y, int destx, int desty, int move) {

        if(move == UPPER_BOUND) {
            /* lets put an upper bound to avoid stack overflow */
            return A_BIG_NUMBER;
        }

        if(x == 6 && y ==5) {
            board[6][5] = 1;
            return 1;
        }
        int min = A_BIG_NUMBER;
        for (int i = 0 ; i < xer.length; i++) {
            if (isMoveGood(x + xer[i], y + yer[i])) {
                if(board[x + xer[i]][y + yer[i]] != 0) {
                    min = Integer.min(min, 1 + board[x +xer[i]] [y +yer[i]]);                   
                } else {
                    min = Integer.min(min, 1 + solution(x + xer[i], y + yer[i], destx, desty, move + 1));   
                }                   
            }
        }   
        board[x][y] = min;
        return min;
    }


    private boolean isMoveGood(int x, int y) {
        if (x >= 0 && x < board.length && y >= 0 && y < board.length)
            return true;
        return false;
    }


    public static void main(String[] args) {

        int destX = 6;
        int destY = 7;
        final Horse h = new Horse();
        System.out.println(h.solution(0, 0, destX, destY, 0));
    }
}

0

ऊपर ग्रीम पाइल के जवाब के jsfiddle से बस माणिक कोड , सभी अतिरिक्त कोड को धारीदार किया और अपने एल्गोरिथ्म द्वारा समाधान प्राप्त करने के लिए केवल रूबी में परिवर्तित कर दिया गया, काम की तरह लगता है। हालांकि अभी भी परीक्षण:

def getBoardOffset(board)
  return board.length / 2
end

def setMoveCount(x, y, count, board)
  offset = getBoardOffset(board)
  board[y + offset][x + offset] = count
end

def getMoveCount(x, y, board)
    offset = getBoardOffset(board)
    row = board[y + offset]
    return row[x + offset]
end

def isBottomOfVerticalCase(x, y)
    return (y - 2 * x) % 4 == 0
end

def isPrimaryDiagonalCase(x, y)
    return (x + y) % 2 == 0
end

def isSecondaryDiagonalCase(x, y)
    return (x + y) % 2 == 1
end

def simplifyBySymmetry(x, y)
    x = x.abs
    y = y.abs
    if (y < x)
      t = x
      x = y
      y = t
    end
    return {x: x, y: y}
end

def getPrimaryDiagonalCaseMoveCount(x, y)
    var diagonalOffset = y + x
    var diagonalIntersect = diagonalOffset / 2
    return ((diagonalIntersect + 2) / 3).floor * 2
end

def getSpecialCaseMoveCount(x, y)
    specials = [{
            x: 0,
            y: 0,
            d: 0
        },
        {
            x: 0,
            y: 1,
            d: 3
        },
        {
            x: 0,
            y: 2,
            d: 2
        },
        {
            x: 0,
            y: 3,
            d: 3
        },
        {
            x: 2,
            y: 2,
            d: 4
        },
        {
            x: 1,
            y: 1,
            d: 2
        },
        {
            x: 3,
            y: 3,
            d: 2
        }
    ];
    matchingSpecial=nil
    specials.each do |special|
      if (special[:x] == x && special[:y] == y)
        matchingSpecial = special
      end
    end
    if (matchingSpecial)
      return matchingSpecial[:d]
    end
end

def isVerticalCase(x, y)
  return y >= 2 * x
end

def getVerticalCaseMoveCount(x, y)
    normalizedHeight = getNormalizedHeightForVerticalGroupCase(x, y)
    groupIndex = (normalizedHeight/4).floor
    groupStartMoveCount = groupIndex * 2 + x
    return groupStartMoveCount + getIndexInVerticalGroup(x, y)
end

def getIndexInVerticalGroup(x, y)
    return getNormalizedHeightForVerticalGroupCase(x, y) % 4
end

def getYOffsetForVerticalGroupCase(x) 
    return x * 2
end

def getNormalizedHeightForVerticalGroupCase(x, y)
    return y - getYOffsetForVerticalGroupCase(x)
end

def getSecondaryDiagonalCaseMoveCount(x, y)
    diagonalOffset = y + x
    diagonalIntersect = diagonalOffset / 2 - 1
    return ((diagonalIntersect + 2) / 3).floor * 2 + 1
end

def getMoveCountO1(x, y)
    newXY = simplifyBySymmetry(x, y)
    x = newXY[:x]
    y = newXY[:y]
    specialMoveCount = getSpecialCaseMoveCount(x ,y)
    if (specialMoveCount != nil)
      return specialMoveCount
    elsif (isVerticalCase(x, y))
      return getVerticalCaseMoveCount(x ,y)
    elsif (isPrimaryDiagonalCase(x, y))
      return getPrimaryDiagonalCaseMoveCount(x ,y)
    elsif (isSecondaryDiagonalCase(x, y))
      return getSecondaryDiagonalCaseMoveCount(x ,y)
    end
end

def solution(x ,y)
  return getMoveCountO1(x, y)
end


puts solution(0,0)

यदि किसी को पूर्ण कोड की आवश्यकता है तो किसी को कोड परिवर्तित करने से बचाने का केवल इरादा है।


0

जूल्स मे के फ़ंक्शन का PHP संस्करण यहां दिया गया है

function knightDistance($x, $y)
{
    $x = abs($x);
    $y = abs($y);

    if($x < $y)
    {
        $tmp = $x;
        $x = $y;
        $y = $tmp;
    }

    if($x > 2 * $y)
    {
        $n7 = 0;
        $n8 = floor(($x + 2*$y) / 4);
        $n10 = floor(($x - 2*$y +1) / 4);
    }
    else
    {
        $n7 = floor((2*$y - $x) / 3);
        $n8 = floor((2*$x - $y) / 3);
        $n10 = 0;
    }

    $x -= 2 * $n8 + $n7 + 2 * $n10;
    $y -= $n8 + 2 * $n7 - $n10;

    if($x == 1 && $y == 0)
    {
        if($n8 > 0)
        {
            $x = 3;
            $y = 1;
            $n8--;
        }
    }
    if($x == 2 && $y == 2)
    {
        if($n8 > 0)
        {
            $x = 3;
            $y = 1;
            $n8--;
            $n7++;
        }
    }

    $cheatsheet = [[0, 3, 2], [2, 0, 2], [4]];

    return $n7 + $n8 + $n10 + $cheatsheet [$y][$x-$y];
}

0

यहाँ मेरा कार्यक्रम है। यह एक सही समाधान नहीं है। पुनरावर्तन फ़ंक्शन में बहुत सारे परिवर्तन करने हैं। लेकिन यह अंतिम परिणाम एकदम सही है। मैंने थोड़ा अनुकूलन करने की कोशिश की।

public class KnightKing2 {
    private static int tempCount = 0;

    public static void main(String[] args) throws IOException {
        Scanner in = new Scanner(System.in);
        int ip1 = Integer.parseInt(in.nextLine().trim());
        int ip2 = Integer.parseInt(in.nextLine().trim());
        int ip3 = Integer.parseInt(in.nextLine().trim());
        int ip4 = Integer.parseInt(in.nextLine().trim());
        in.close();
        int output = getStepCount(ip1, ip2, ip3, ip4);
        System.out.println("Shortest Path :" + tempCount);

    }

    // 2 1 6 5 -> 4
    // 6 6 5 5 -> 2

    public static int getStepCount(int input1, int input2, int input3, int input4) {
        return recurse(0, input1, input2, input3, input4);

    }

    private static int recurse(int count, int tx, int ty, int kx, int ky) {

        if (isSolved(tx, ty, kx, ky)) {
            int ccount = count+1;
            System.out.println("COUNT: "+count+"--"+tx+","+ty+","+ccount);
            if((tempCount==0) || (ccount<=tempCount)){
                tempCount = ccount;
            }
            return ccount;
        }

            if ((tempCount==0 || count < tempCount) && ((tx < kx+2) && (ty < ky+2))) {
                if (!(tx + 2 > 8) && !(ty + 1 > 8)) {
                    rightTop(count, tx, ty, kx, ky);

                }
                if (!(tx + 2 > 8) && !(ty - 1 < 0)) {
                    rightBottom(count, tx, ty, kx, ky);
                }
                if (!(tx + 1 > 8) && !(ty + 2 > 8)) {
                    topRight(count, tx, ty, kx, ky);
                }
                if (!(tx - 1 < 0) && !(ty + 2 > 8)) {
                    topLeft(count, tx, ty, kx, ky);
                }
                if (!(tx + 1 > 8) && !(ty - 2 < 0)) {
                     bottomRight(count, tx, ty, kx, ky);
                }
                if (!(tx - 1 < 0) && !(ty - 2 < 0)) {
                     bottomLeft(count, tx, ty, kx, ky);
                }
                if (!(tx - 2 < 0) && !(ty + 1 > 8)) {
                    leftTop(count, tx, ty, kx, ky);
                }
                if (!(tx - 2 < 0) && !(ty - 1 < 0)) {
                    leftBottom(count, tx, ty, kx, ky);
                }
            }

        return count;

    }

    private static int rightTop(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx + 2, ty + 1, kx, ky);

    }

    private static int topRight(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx + 1, ty + 2, kx, ky);
    }

    private static int rightBottom(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx + 2, ty - 1, kx, ky);
    }

    private static int bottomRight(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx + 1, ty - 2, kx, ky);
    }

    private static int topLeft(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx - 1, ty + 2, kx, ky);
    }

    private static int bottomLeft(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx - 1, ty - 2, kx, ky);
    }

    private static int leftTop(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx - 2, ty + 1, kx, ky);
    }

    private static int leftBottom(int count, int tx, int ty, int kx, int ky) {
        return count + recurse(count + 1, tx - 2, ty - 1, kx, ky);
    }

    private static boolean isSolved(int tx, int ty, int kx, int ky) {
        boolean solved = false;
        if ((tx == kx) && (ty == ky)) {
            solved = true;
        } else if ((tx + 2 == kx) && (ty + 1 == ky)) { // right top
            solved = true;
        } else if ((tx + 2 == kx) && (ty - 1 == ky)) { // right bottom
            solved = true;
        } else if ((ty + 2 == ky) && (tx + 1 == kx)) {// top right
            solved = true;
        } else if ((ty + 2 == ky) && (tx - 1 == kx)) {// top left
            solved = true;
        } else if ((tx - 2 == kx) && (ty + 1 == ky)) { // left top
            solved = true;
        } else if ((tx - 2 == kx) && (ty - 1 == ky)) {// left bottom
            solved = true;
        } else if ((ty - 2 == ky) && (tx + 1 == kx)) { // bottom right
            solved = true;
        } else if ((ty - 2 == ky) && (tx - 1 == kx)) { // bottom left
            solved = true;
        }

        return solved;
    }

}

1
डुप्लिकेट से बचने के लिए इसे और अधिक अनुकूलित किया जा सकता है।
अरुण

-1

यहाँ मुस्तफा सर्दार lanlı कोड पर आधारित एक C संस्करण है जो एक परिमित बोर्ड के लिए काम करता है:

#include <stdio.h>
#include <math.h>

#define test(x1, y1, x2, y2) (sx == x1 && sy == y1 &&tx == x2 &&ty == y2) || (sx == x2 && sy == y2 && tx == x1 && ty==y1)

int distance(int sx, int sy, int tx, int ty) {
    int x, y, t;
    double delta;

    // special corner cases 
    if (test(1, 1, 2, 2) || 
        test(7, 7, 8, 8) || 
        test(7, 2, 8, 1) || 
        test(1, 8, 2, 7))
        return 4;

    // axes symmetry 
    x = abs(sx - tx);
    y = abs(sy - ty);

    // diagonal symmetry 
    if (x < y) {
        t = x;
        x = y;
        y = t;
    }

    // 2 corner cases
    if (x == 1 && y == 0)
        return 3;
    if (x == 2 && y == 2)
        return 4;

    // main
    delta = x - y;
    if (y > delta) {
        return (int)(delta - 2 * floor((delta - y) / 3));
    }
    else {
        return (int)(delta - 2 * floor((delta - y) / 4));
    }
}

एक पुनरावर्ती समाधान के खिलाफ सबूत के साथ यहां परीक्षण करें


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