Şövalyenin Satranç Tahtasındaki En Kısa Yolu


96

Yaklaşan bir programlama yarışması için pratik yapıyorum ve tamamen şaşkına döndüğüm bir soru ile karşılaştım. Ancak, bunun asla ortaya çıkmayacağını parmaklarımı çaprazlamak yerine şimdi öğrenmem gereken bir kavram olduğunu hissediyorum.

Temel olarak, satranç tahtasındaki bir at taşıyla ilgilenir. Size iki giriş verilir: başlangıç ​​konumu ve bitiş konumu. Amaç, atın hedef konuma ulaşmak için izleyebileceği en kısa yolu hesaplamak ve yazdırmaktır.

Asla en kısa yol benzeri şeylerle uğraşmadım ve nereden başlayacağımı bile bilmiyorum. Bununla mücadele etmek için hangi mantığı kullanmalıyım?

Not: Herhangi bir ilgisi varsa, atın normal hareketlerini, bir atın yapabileceği (potansiyel olarak) sekiz hamle ile oluşturulan karenin dört köşesine de hareket etmesine izin vererek, atın normal hareketlerini tamamlamanızı istiyorlar. şövalyenin yeri.


PS'yi açıklar mısınız? Yani bir at E4'teyse C2, C6, G2 ve G6'ya gidebilir mi?
Steve Tjoa

Evet, normal hareketlerine ek olarak.
Kyle Hughes

1
İşte problemin bazı matematiksel analizi: math.stackexchange.com/questions/104700/…
Graeme Pyle

Yanıtlar:


28

Burada, mevcut tüm hareketlerin bağlantılı olduğu (değer = 1) ve kullanılamayan hareketlerin bağlantısının kesildiği (değer = 0) bir grafiğiniz var, seyrek matris şöyle olacaktır:

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

Ve bir grafikteki iki noktanın en kısa yolu http://en.wikipedia.org/wiki/Dijkstra's_algorithm kullanılarak bulunabilir.

Wikipedia sayfasından sözde kod:

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[]

DÜZENLE:

  1. moron olarak, http://en.wikipedia.org/wiki/A*_algorithm'i kullanmanın daha hızlı olabileceğini söyledi.
  2. en hızlı yol, tüm mesafeleri önceden hesaplamak ve 8x8 tam matrise kaydetmektir. Ben buna hile derdim ve sadece sorun küçük olduğu için işe yarıyor. Ancak bazen yarışmalar programınızın ne kadar hızlı çalıştığını kontrol eder.
  3. Esas nokta, bir programlama yarışmasına hazırlanıyorsanız, Dijkstra's dahil ortak algoritmaları bilmeniz gerektiğidir. İyi bir başlangıç ​​noktası Introduction to AlgorithmsISBN 0-262-03384-4 okumaktır. Ya da wikipedia'yı deneyebilirsiniz, http://en.wikipedia.org/wiki/List_of_algorithms

Bu, Mustafa'nın aşağıdaki çözümüyle kıyaslandığında karmaşık görünüyor.
lpapp

Ulaşılamaz hareketle ne demek istiyorsun? Bir şövalye her kareye ulaşabilir!
everlasto

51

DÜZENLEME: Simon'ın burada sunulan formülü düzelttiği cevabına bakın .

Aslında bir O (1) formülü var

Bu görselleştirmek için yaptığım bir resim (Bir atın N'inci hamlede ulaşabileceği kareler aynı renge boyanmıştır). Şövalye Hamlesi

Buradaki deseni fark edebiliyor musunuz?

Biz desen görebilirsiniz rağmen, fonksiyonunu bulmak gerçekten zor f( x , y )hamle sayısı meydanına gitmek için gerekli döndürdüğü ( 0 , 0 )kareye( x , y )

Ama işte ne zaman işe yarayan formül 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 );
}

Not: Bu soru SACO 2007 1. Günde soruldu
ve çözümler burada


8
Bu formülü nasıl oluşturduğunuzu tarif etme şansınız var mı?
kybernetikos

3
Bu kod çalışıyor mu? Bir at (0,0) konumunda a konumundaysa ve onu (1,0) noktasına taşımak istiyorum. Bu, 0 <= y <= x'i sağlar. delta = 1-0 = 1. y, deltadan (0 <1) büyük değildir. Bu, diğer davaya gideceğim anlamına geliyor. delta - 2 * ((delta - y) / 4) = 1-2 ((1-0) / 4) = 1-1 / 2 = 1. Atı (0,0) 'dan (1,0)' a tek hamlede taşıyabileceğim hiçbir şey yok. Soru bu algoritma işe yarıyor mu? Ya da neyi yanlış yapıyorum?
SimpleApp

3
Görünüşe göre sadece doğrudan olası pozisyonlar için çalışıyor. Ancak kullanıcı (2,2) sağlarsa 0 döndürür ve kullanıcı (4,4) sağlarsa yanlış olan 2 döndürür.
yunas

6
Öyle olmalı 2 * floor((y - delta) / 3) + deltave delta - 2 * floor((delta - y) / 4). Bu yarışma sayfasındaki resmi çözüm, ancak yanlış. Bu ilk denklem (kimden if) yanlış cevaplar verir. 2001x2001 büyük (ancak mantıksal olarak sınırsız) olan satranç tahtasında [-1000..1000] x [-1000..1000], verilen yanıt 4.004.001 alandan 2.669.329 doğru sayıyor (% 66.66). Döngüsüz çalışma çözümünü bilen var mı?
Robo Robok

2
Bu çözümün işe yaramadığına katılıyorum. Çalışan bir O (1) çözümü için stackoverflow.com/a/26888893/4288232 gibi diğer yanıtlara bakın .
TimSC

45

İşte doğru bir O (1) çözümü, ancak atın yalnızca bir satranç atı gibi ve sonsuz bir satranç tahtası üzerinde hareket ettiği durum için:

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

Bunu bulmanın anahtarı, tahtayı çizdiğinizde ortaya çıkan kalıpları fark etmektir. Aşağıdaki diyagramda, karedeki sayı, o kareye ulaşmak için gereken minimum hareket sayısıdır (bunu bulmak için önce enine aramayı kullanabilirsiniz):

Desenler

Çözüm eksenler ve köşegenler boyunca simetrik olduğundan, sadece x> = 0 ve y> = x durumunu çizdim.

Sol alt blok başlangıç ​​pozisyonudur ve bloklardaki sayılar bu bloklara ulaşmak için gereken minimum hareket sayısını temsil eder.

Dikkat edilmesi gereken 3 model vardır:

  • 4'lü artan mavi dikey gruplar
  • "Birincil" kırmızı köşegenler (ters eğik çizgi gibi sol üstten sağ alta doğru uzanırlar)
  • "İkincil" yeşil köşegenler (kırmızı ile aynı yönelim)

(Her iki köşegen kümesini de üstten soldan sağa doğru gördüğünüzden emin olun. Sabit bir hareket sayıları vardır. Sol alt-sağ köşegenler çok daha karmaşıktır.)

Her biri için formül türetebilirsiniz. Sarı bloklar özel durumlardır. Böylece çözüm şu hale gelir:

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);

}

en zoru dikey gruplar olmak üzere:

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);

}

Diğer vakalar için kemana bakın.

Belki özlediğim daha basit veya daha zarif desenler vardır? Öyleyse, onları görmeyi çok isterim. Özellikle mavi dikey kasalarda bazı köşegen desenler görüyorum, ancak bunları keşfetmedim. Ne olursa olsun, bu çözüm yine de O (1) kısıtlamasını karşılar.


Bu (değişmez) köşe durumlarını ele almıyor gibi görünüyor. Eğer "0" tahtada (a1) sol alt kareyse, o zaman en yakın "2" boşluğuna (b2) iki hamlede ulaşamazsınız. Çünkü bunu yapmak için ilk hareketiniz (a3) ​​'ün solundaki var olmayan boşlukta olmalıdır.
John Hascall

Doğru, cevabımı sonsuz satranç tahtası varsayımını içerecek şekilde değiştirdim
Graeme Pyle

@JonatasWalker Lütfen açıklayınız, (8,0) 'dan (0,0)' a giden bir problem görmüyorum. 4 hamle mi sürüyor?
Graeme Pyle

Özür dilerim @GraemePyle, benim hatam, yorumumu kaldırıyorum.
Jonatas Walker

2
merhaba @GraemePyle - Size katılıyorum, bu en iyi genel programlama yaklaşımıdır. Bu arada harika diyagram!
Fattie

22

Son zamanlarda karşılaştığım çok ilginç bir sorun. Bazı çözümleri inceledikten sonra SACO 2007 1. Gün çözümlerindeO(1) time and space complexity verilen analitik formülü ( ) kurtarmaya çalıştım .

Öncelikle, formülü düzeltmeme yardımcı olan çok güzel görselleştirme için Graeme Pyle'ı takdir etmek istiyorum .

Bazı nedenlerden dolayı (belki sadeleştirme veya güzellik için veya sadece bir hata için) operatöre minusişareti taşıdılar floor, sonuç olarak yanlış formüle sahipler floor(-a) != -floor(a) for any a.

İşte doğru analitik formül:

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

Formül, aşağıdaki kod parçacığında desen için tatmin edici olmayan ve kodlanmış (1,0) ve (2,2) köşe durumları dışında tüm (x, y) çiftleri için (eksenler ve çapraz simetri uygulandıktan sonra) çalışır:

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>

Not: jQuery yalnızca gösterim amacıyla kullanılır, kod için distanceişleve bakın .


2
@OlegAbrazhaev "Mesafe" fonksiyonu analitik bir fonksiyondur ve O (1) zamanında verilen (x, y) pozisyon için adım sayısını hesaplayabilir. Temel olarak bu formülde tahtaya bağlı değiliz (sanırım "sonsuz tahta" derken bu özelliği kastediyorsunuz), dolayısıyla işe yarayacaktır.
simon

2
@simon Lütfen birisi ana formülü açıklayabilir mi? Bunu basit kelimelerle açıklamakta
zorlanıyorum

1
@MarBVI Eğer y = x çizgisine yaklaşırsak, her harekette y = x çizgisine yakın kalarak x + y'yi 3 azaltabiliriz. Y = 0 çizgisine yaklaşırsak, her harekette y = 0 çizgisine yakın kalarak x'i 2 azaltabiliriz. Bu yüzden 2 durumumuz var, daha doğrusu burada belirli bir çizgiye yakın diyerek demek istediğim: 1. y = x çizgisine yakın derken y = x ve y = x / 2 çizgileriyle sınırlı bölümü kastediyorum (y> x / 2 ). 2. y = 0 çizgisine yakın derken y = 0 ve y = x / 2 çizgileriyle (y <x / 2) sınırlanan bölümü kastediyorum. Yukarıda belirtilenlerin hepsini ele alırsak ve Math.floor'u kaldırırsak ve ana formülü basitleştirirsek aşağıdaki formülü alacağız: if (y> x / 2) ise {return (x + y) / 3} else {return x / 2}
simon

1
@simon harika, bu daha açık hale getiriyor ... zamanınız için
teşekkürler

1
Her ihtimale karşı, BAPC2017 yarışmasında, bu formülün mükemmel bir şekilde çözdüğü sonsuz bir tahtada Knight's Marathon adında bir soru vardı. 2017.bapc.eu/files/preliminaries_problems.pdf
Amir-Mousavi

19

Evet, Dijkstra ve BFS size cevabı verecektir, ancak bence bu problemin satranç bağlamı, özellikle sonsuz bir satranç tahtasında, genel bir kısa yol algoritmasından çok daha hızlı bir çözüm sağlayabilecek bilgi sağlar.

Basit olması için satranç tahtasını (x, y) düzlemi olarak tanımlayalım. Amaç, yalnızca (+ -1, + -2), (+ -2, + -1) ve (+ -2) aday adımlarını kullanarak (x0, y0) - (x1, y1) arasındaki en kısa yolu bulmaktır. , + -2), sorunun PS'sinde açıklandığı gibi

İşte yeni gözlem: köşeleri olan bir kare çizin (x-4, y-4), (x-4, y + 4), (x + 4, y-4), (x + 4, y + 4) . Bu set (ona S4 diyelim) 32 puan içeriyor. Bu 32 noktadan (x, y) herhangi birinden en kısa yol, tam olarak iki hareket gerektirir .

S3 kümesindeki 24 noktanın herhangi birinden (benzer şekilde tanımlanmıştır) (x, y) 'ye en kısa yol en az iki hareket gerektirir .

Bu nedenle, | x1-x0 |> 4 veya | y1-y0 |> 4 ise, (x0, y0) - (x1, y1) arasındaki en kısa yol, (x0, y0) ile (x0, y0) arasındaki en kısa yoldan tam olarak iki hareket daha büyüktür. S4. Ve ikinci sorun, basit yineleme ile hızlı bir şekilde çözülebilir.

N = max (| x1-x0 |, | y1-y0 |) olsun. N> = 4 ise, (x0, y0) 'dan (x1, y1)' e giden en kısa yol ceil (N / 2) adımlarına sahiptir.


1
Bu cevap konusunda kafası karışan sadece ben miyim? "köşeli bir kare çizin (x-4, y-4), (x-4, y + 4), (x + 4, y-4), (x + 4, y + 4). Bu set (çağrı it S4) 32 puan içerir ". Hayır değil, 9x9 kare olduğu için 81 içeriyor mu? Ayrıca, "N = max (| x1-x0 |, | y1-y0 |) olsun. N> = 4 ise, (x0, y0) - (x1, y1) arasındaki en kısa yol ceil (N / 2) 'ye sahiptir. adımlar. " Bu doğru değil, örneğin x0 = 0, y0 = 0, x1 = 4, y1 = 4, en kısa yol 4, formülün önerdiği gibi 2 değil.
satoshi

1
(1) Küme, sadece karenin sınırındaki noktalara atıfta bulunur. 32 noktası / konumu vardır. (2) Posterin tamamlayıcı hamleler hakkındaki notunu dikkate aldığınızda (orijinal gönderideki yorumlara da bakın), minimum hamle sayısı iki olur.
Steve Tjoa

Teşekkürler, artık mantıklı :)
satoshi

ya bir tahta sonsuzsa? bu durumda sadece BFS iyi çalışacaktır
Oleg Abrazhaev

@SteveTjoa üzgünüm, bir şövalye için imkansız olduğu için (+ -2, + -2) hareketten neden bahsettiğinizi anlayamıyorum
Pavel Bely

12

Yukarıdaki O (1) yanıtı [ https://stackoverflow.com/a/8778592/4288232 by Mustafa Serdar Şanlı] gerçekten işe yaramıyor. ((1,0) veya (2,2) gibi açık uç durumları bir yana (1,1) veya (3,2) veya (4,4) işaretleyin).

Aşağıda, işe yarayan çok daha çirkin bir çözüm (python) bulunmaktadır (ek "testler" ile):

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
Cevaplara SO üzerinde gerçekten işe yaramaz aboveveya belowişe yaramaz diye değinmek.
Petr Peller

1
İşte python 2/3 sürümüm. Çözme işlevini basitleştirmeye çalıştım ama bu kolay değil! gist.github.com/TimSC/8b9a80033f3a22a708a4b9741931c591
TimSC

9

Yapmanız gereken şey, atın olası hamlelerini bir grafik olarak düşünmektir, burada tahtadaki her konum bir düğümdür ve olası hareketler bir kenar olarak başka bir konuma hareket eder. Dijkstra algoritmasına gerek yoktur, çünkü her kenar aynı ağırlık veya mesafeye sahiptir (bunların hepsi yapmak kadar kolay veya kısadır). Başlangıç ​​noktanızdan son konuma ulaşana kadar bir BFS araması yapabilirsiniz.


1
+ !, bu özel sorun için BFS yeterlidir.
TiansHUo

3
BFS yeterli olabilir, ancak birçok sorgu için düz bir BST patlayacaktır - ziyaret ettiğiniz kareleri önbelleğe almanız gerekecektir. Ve sonra BFS biraz Dijkstra'nın algoritmasına benzemeye başlar ...
Charles Stewart

BFS ağacının yalnızca ileriye doğru büyümesi için halihazırda seyahat ettiğimiz tüm pozisyonları takip etmenin en iyi yolu ne olurdu ve yeni bir noktadan kullanılabilir düğümler keşfettiğimizde, eski düğümü tekrar eklemeye son vermeyiz ... ve sıkışıp kalmayız ... sonsuz bir döngü!
Nitish Upreti

Sanırım son şövalye pozisyonumuzu kaydederek yapabilir miyiz?
Nitish Upreti

7

Python'daki ilk ilkelerden çözüm

Bu problemle ilk kez bir Codility testinde karşılaştım. Çözmem için bana 30 dakika verdiler - bu sonuca varmam çok daha uzun sürdü! Sorun şuydu: Bir atın 0,0'dan x'e, sadece yasal Şövalye hareketlerini kullanarak gitmesi için kaç hamle yapması gerektiğiydi. x ve y aşağı yukarı sınırsızdı (bu yüzden burada basit bir 8x8 satranç tahtasından bahsetmiyoruz).

Bir O (1) çözümü istediler. Programın problemi açıkça çözdüğü bir çözüm istedim (yani Graeme'nin modelinden daha açık bir şekilde doğru olan bir şeyi istedim - bakmadığınız yerlerde kalıpların parçalanma alışkanlığı var) ve gerçekten bir programa güvenmemek istedim. tartışmasız formül, Mustafa'nın çözümünde olduğu gibi

Öyleyse, değeri ne olursa olsun, işte benim çözümüm. Başkalarının yaptığı gibi, çözümün eksenler ve köşegenler etrafında simetrik olduğunu belirterek başlayın, bu yüzden sadece 0> = y> = x için çözmemiz gerekir. Açıklamanın (ve kodun) basitliği için sorunu tersine çevireceğim: at x, y'den başlıyor ve 0,0'ı hedefliyor.

Diyelim ki sorunu kökenine kadar küçültelim. Zaman içinde 'vicinty'nin aslında ne anlama geldiğini öğreneceğiz, ancak şimdilik, bir kopya kağıdına (sol alttaki başlangıç) bazı çözümler yazalım:

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

Yani, ızgarada x, y verildiğinde, başlangıç ​​noktasına hareketlerin sayısını okuyabiliriz.

Şebekenin dışında başladıysak, ona geri dönmeliyiz. Y = x / 2 ile temsil edilen çizgi olan 'orta çizgiyi' tanıtıyoruz. Bu satırdaki x, y noktasındaki herhangi bir at, bir dizi saat 8 hamlesi (yani: (-2, -1) hamle) kullanarak hile sayfasına geri dönebilir. Eğer x, y orta çizginin üstündeyse, o zaman art arda saat 8 ve saat 7 hareketlerine ihtiyacımız olacak ve eğer orta çizginin altındaysa, art arda saat 8 ve 10'a ihtiyacımız olacak. saat hareket ediyor. Burada dikkat edilmesi gereken iki nokta:

  • Bu diziler kanıtlanabilecek en kısa yollardır. (Kanıtlamamı istiyor musun yoksa açık mı?)
  • Sadece bu tür hamlelerin sayısını önemsiyoruz. Hareketleri herhangi bir sırayla karıştırıp eşleştirebiliriz.

Öyleyse, orta hat üstü hareketlere bakalım. İddia ettiğimiz şey şudur:

  • (dx; dy) = (2,1; 1,2) (n8; n7) (matris gösterimi, matematik dizgi olmadan - sütun vektörü (dx; dy), kare matrisin sütun vektörüyle (n8; n7) çarpımına eşittir - saat 8 hareket sayısı ve saat 7 hareket sayısı) ve benzer şekilde;

  • (dx; dy) = (2,2; 1, -1) (n8; n10)

Dx, dy'nin kabaca (x, y) olacağını iddia ediyorum, bu nedenle (x-dx, y-dy) başlangıç ​​noktasına yakın olacaktır ('yakınlık' ne olursa olsun).

Kodda bu terimleri hesaplayan iki satır bunların çözümüdür, ancak bazı yararlı özelliklere sahip olmaları için seçilirler:

  • Orta hat üzerindeki formül (x, y) 'yi (0,0), (1,1) veya (2,2)' den birine taşır.
  • Orta hat altındaki formül (x, y) 'yi (0,0), (1,0), (2,0) veya (1,1)' den birine taşır.

(Bunların kanıtlarını ister misiniz?) Yani, Şövalye'nin mesafesi n7, n8, n10 ve hile sayfasının [x-dx, y-dy] toplamı olacak ve hile sayfamız buna indirgenecek:

. . 4
. 2 .
0 3 2

Şimdi, bu hikayenin tam olarak sonu değil. Alt sıradaki 3'e bakın. Buna ulaşmanın tek yolu:

  • Orada başladık veya
  • Oraya saat 8 ve 10 yönünde bir dizi hareketle hareket ettik. Ancak son hamle saat 8 ise (hamlelerimizi herhangi bir sırayla yapabildiğimiz için buna hak kazanır), o zaman aslında uzaklığı 2 olan (yapabileceğiniz gibi) (3,1) 'i geçmiş olmalıyız. orijinal kopya sayfasından bakın). Öyleyse yapmamız gereken şey, saat 8 yönünde geriye doğru bir hamle yapmak ve toplamda iki hareket tasarrufu yapmak.

Sağ üstteki 4 ile benzer bir optimizasyon var. Oradan başlamak dışında, buna ulaşmanın tek yolu (4,3) 'ten saat 8 yönünde hareket etmektir. Bu hile kağıdında değil, ama eğer orada olsaydı, mesafesi 3 olurdu, çünkü saat 7'yi (3,1) konumuna getirebilirdik, bu da yalnızca 2'lik bir mesafeye sahip olabilir. Saat 8 yönünde hareket edin ve ardından saat 7 yönünde bir ileri gidin.

Yani, hile sayfasına bir sayı daha eklememiz gerekiyor:

. . 4
. 2 . 2
0 3 2

(Not: (0,1) ve (0,2) 'den çok sayıda geri izleme optimizasyonu var, ancak çözücü bizi asla oraya götürmeyeceği için endişelenmemize gerek yok.)

Öyleyse burada, bunu değerlendirmek için bir Python kodu var:

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]

Bu arada, gerçek bir rotayı bilmek istiyorsanız, o zaman bu algoritma bunu da sağlar: bu basitçe n7 saat 7 yönünde hareketlerin bir ardışıklığıdır, ardından n8 saat 8 yönünde hareketler, n10 10- saat hareketleri ve hile sayfası tarafından dikte edilen dans ne olursa olsun (ki bu da kopya kağıdında olabilir).

Şimdi: Bunun doğru olduğunu nasıl kanıtlayabilirim? Bu sonuçları bir doğru cevaplar tablosuyla karşılaştırmak yeterli değildir, çünkü sorunun kendisi sınırsızdır. Ancak şöyle diyebiliriz ki, At'ın bir karenin s karesi mesafesi d ise, o zaman {m}, s'den yasal hamleler kümesiyse, At'ın (s + m) mesafesi d-1 veya d + 1 olmalıdır. tüm m için. (Bunun bir kanıtına ihtiyacınız var mı?) Ayrıca, s başlangıç ​​noktası olmadığı sürece, mesafesi d-1 olan böyle en az bir kare olmalıdır. Yani, bu özelliğin her kare için geçerli olduğunu göstererek doğruluğu kanıtlayabiliriz. Böylece:

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")

Alternatif olarak, herhangi bir karenin doğruluğunu, yokuş aşağıdan başlangıç ​​noktasına giden rotayı takip ederek kanıtlayabiliriz. İlk olarak, yukarıdaki gibi makul olup olmadığını kontrol edin, ardından mesafe (s + m) == d-1 olacak şekilde herhangi bir s + m seçin. Başlangıç ​​noktasına ulaşana kadar tekrarlayın.

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.

Henüz grafikler çalışmadım ... basit diziler aracılığıyla uygulama problemi gereği, bundan başka bir çözüm üretemedim. Pozisyonları dereceler ve dosyalar (normal satranç gösterimi) olarak değil, dizi indeksleri olarak değerlendirdim. Bilginize, bu yalnızca 8 * 8 satranç tahtası içindir. Herhangi bir iyileştirme tavsiyesi her zaman memnuniyetle karşılanır.

* Mantığı anlamanız için yorumlar yeterli olmalıdır. Ancak her zaman sorabilirsiniz.

* DEV-C ++ 4.9.9.2 derleyicisinde (Bloodshed Yazılımı) kontrol edildi.


2

Bunun size de yardımcı olabileceğini düşünüyorum ..

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

ve çözümü elde etmek için Dinamik Programlamayı kullanma.

Not: Grafiğin düğümlerini ve kenarlarını bildirme zahmetine girmeden BFS kullanır.


1

İşte Perl'de uygulanan bu özel sorun için bir çözüm. En kısa yollardan birini gösterecektir - bazı durumlarda birden fazla yol olabilir.

Yukarıda açıklanan algoritmalardan hiçbirini kullanmadım - ancak bunu diğer çözümlerle karşılaştırmak güzel olurdu.

#!/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

Sadece Graeme Pyle'ın cevabının jsfiddle'ından gelen ruby ​​kodu, tüm fazladan kodu şeritledi ve sadece algoritmasıyla çözüm elde etmek için kalanını Ruby'ye dönüştürdü, çalışıyor gibi görünüyor. Yine de test ediyor:

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)

Tek amaç, tam koda ihtiyaç duyan birisinin kodu dönüştürürken biraz zaman kazanmasıdır.


0

Jules May'in işlevinin PHP sürümü burada

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

İşte programım. Bu mükemmel bir çözüm değil. Özyineleme işlevinde yapılacak pek çok değişiklik vardır. Ancak bu nihai sonuç mükemmel. Biraz optimize etmeye çalıştım.

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
Yinelemeleri önlemek için daha fazla optimize edilebilir.
Arun

-1

İşte Mustafa Serdar Şanlı koduna dayalı, sonlu bir pano için çalışan bir C versiyonu:

#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));
    }
}

Özyinelemeli bir çözüme karşı kanıtla burada test edin


1
Sonlu sayıda vakayı test etmek bir kanıt değildir.
BlenderBender
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.