1D Atlamalı Dizi Labirenti


17

Esinlenen kule atlama ve 2D Labirent Eksi 1D ile ilgili

Giriş

Göreviniz, belirtilen kurallara uyarak bir dizi labirentinden çıkmak için en kısa yolu bulmaktır.

Meydan okuma

1D bir dizi , bir ile N unsurlardan oluşan bir labirent olarak kabul edilebilir N göstergesi olan nokta nokta, k sahip noktalara bağlı k + bir [ k ] ve k - bir [ k tek yönlü bir şekilde]. Başka bir deyişle, ileri veya geri tam olarak atlayabilir bir [ k indeksi ile noktadan] adımlar k . Dizinin sınırları dışında dizini olan noktalar labirent dışında değerlendirilir.

Bunu göstermek için aşağıdaki diziyi göz önünde bulundurun,

[0,8,5,9,4,1,1,1,2,1,2]

Şu anda 5. öğedeysek, öğe 4 olduğu için, 9. öğeye 4 adım veya 1. öğeye 4 adım geriye atlayabiliriz. İkincisini yaparsak, başka hareketin mümkün olmadığını gösteren 0 elementiyle sonuçlanırız. Birincisini yaparsak, 9. element 2 olduğu için, yine 2 olan 11. elemente atlamayı seçebiliriz ve sonra tekrar "13. element" e atlayabiliriz. ve labirente çıkış olarak kabul edilir.

Ortadaki elemandan başlayalım, labirentten çıkmanın bir yolu 1 adım geri, 4 adım ileri, 2 adım ileri ve tekrar 2 adım ileri atlamaktır, bu da dizi olarak ifade edilebilir [-1,4,2,2]. Alternatif olarak [4,8,10,12], tüm ara ve son noktaların sıfır temelli dizinini (1 temelli dizin de iyidir) veya sadece işaretlerini kaydeden dizi ile ifade edebilirsiniz [-1,1,1,1].

Labirent düşük dizin ucundan kaçmak da sorun yok.

İlk gösterimi kullanmak ve aynı öğeden başlamak [1,1,1,2,2]da bir çözümdür, ancak 4 yerine 5 adım olduğundan optimal değildir.

Görev, dizi labirentinden çıkmak ve yolu çıkarmak için en kısa yolu bulmaktır. Birden fazla optimal yol varsa, bunların herhangi birini veya tümünü çıktısını alabilirsiniz. Çözüm yoksa, sizin tarafınızdan seçilen geçerli bir yoldan fark edilebilecek bir falsy değeri çıkarmalısınız (hiç çıktı üretmemek de sorun değildir).

Basit olması için, dizideki öğelerin sayısı her zaman tek bir sayıdır ve her zaman ortadaki öğeden başlarız.

Test senaryoları

Test senaryoları çeşitli çıktı biçimlerini gösterir, ancak bunlarla sınırlı değilsiniz.

Input
Output

[0,8,5,9,4,1,1,1,2,1,2]
[-1,4,2,2]

[2,3,7,1,2,0,2,8,9]
[2,9] (or [2,-5] or [[2,9],[2,-5]])

[0,1,2,2,3,4,4,4,3,2,2,3,0]
[1,-1,1,1]

[0,1,2,2,4,4,6,6,6,6,6,4,2,1,2,2,0]
[]

gözlük

  • Bir işlev veya tam bir program yazabilirsiniz.

  • Dizi yalnızca negatif olmayan tamsayılar içerir.

  • Herhangi bir standart formdan girdi ve çıktı alabilirsiniz , ancak cevabınızda hangi formu kullandığınızı belirtiniz.

  • Bu , en düşük bayt sayısı kazanır.

  • Her zamanki gibi, burada varsayılan boşluklar uygulanır.


Yanıt benzersiz olsa bile iç içe bir dizi çıkarmak iyi midir? (örn için [0,8,5,9,4,1,1,1,2,1,2], çıkış [[-1,4,2,2]])
Bubbler

@ Kabarcık Evet, iç içe dizi çıktısı alabilirsiniz.
Weijun Zhou

Kaçış yolunu ters sırada döndürmek uygun mudur? Peki [1,1,1,-1]yerine [-1,1,1,1]?
Ton Hospel

@TonHospel Evet, sadece cevabında söyle.
Weijun Zhou

test örneği 2 yanlış görünüyor, açıklayabilir misiniz?
edc65

Yanıtlar:


3

JavaScript (ES6), 117 bayt

0 dizinli ara ve son nokta dizisini veya çözüm yoksa boş bir dizi döndürür.

a=>(g=(x,p,d=a[x])=>1/d?[d,-d].map(d=>p.includes(X=x+d)||g(X,[...p,X])):o=o==''|o[p.length]?p:o)(a.length>>1,o=[])&&o

Çevrimiçi deneyin!

Yorumlananlar

a =>                              // given the maze a[]
  (g = (                          // g = recursive function taking:
    x,                            //   x = current position
    p,                            //   p[] = list of visited cells
    d = a[x]                      //   d = value of current cell
  ) =>                            //
    1 / d ?                       // if d is defined:
      [d, -d].map(d =>            //   for d and -d:
        p.includes(X = x + d) ||  //     if the cell at X = x + d was not yet visited,
        g(X, [...p, X])           //     do a recursive call to g() at this position
      )                           //   end of map()
    :                             // else:
      o =                         //   update o:
        o == '' |                 //     if o was empty
        o[p.length] ?             //     or p is shorter than o:
          p                       //       set o to p
        :                         //     else:
          o                       //       let o unchanged
  )(a.length >> 1, o = [])        // initial call to g(), starting in the middle
  && o                            // return o

3

Kabuk , 22 bayt

ḟȯ¬€ŀ¹FS+o*!¹⌈½L¹ṁπṡ1ŀ

Bir işaret listesi veya bir çözüm yoksa boş bir liste döndürür. Çevrimiçi deneyin!

açıklama

Bu, -1,0,1artan uzunluktaki listeleri kontrol eden ve diziden atlamaya neden olan ilkini döndüren bir kaba kuvvet çözümüdür . Minimum uzunlukta olduğundan 0 saniye içermez.

ḟȯ¬€ŀ¹FS+o*!¹⌈½L¹ṁπṡ1ŀ  Implicit input, say A = [0,1,1]
                     ŀ  Indices of A: [1,2,3]
                 ṁ      Map over them and concatenate:
                  π      Cartesian power
                   ṡ1    of the symmetric range [-1,0,1].
                        Result is B = [[-1],[0],[1],[-1,-1],...,[1,1,1]]
ḟ                       Find the first element of B that satisfies this:
                         Argument is a list, say C = [1,-1].
      F                  Reduce C from the left
             ⌈½L¹        using ceil(length(A)/2) as the initial value
       S+o*!¹            with this function:
                          Arguments are an index of A, say I = 2, and a sign, say S = 1.
           !¹             The element of A at I: 1
         o*               Multiply by S: 1
       S+                 Add to I: 2
                         At the end of the reduction, we have a number I, here 2.
   €ŀ¹                   Is it an element of the indices of A: Yes.
 ȯ¬                      Negate: No.
                        The result is the shortest list C for which I is outside of A.

2

Python 3 , 195 188 179 bayt

def f(a):
 v=len(a);x,*s={v//2},[v//2]
 while all(v>b>-1for*c,b in s)*s:s=[x.add(u)or c+[b,u]for*c,b in s for u in[b+a[b],b-a[b]]if{u}-x]
 return[b[1:]for b in s if not-1<b[-1]<v]

Çevrimiçi deneyin!

Düzenle:

  • 9 bayt kaydedildi all(..)and s => all(..)*s, if u not in x => if{u}-x
    Önceki istismar boolean * list == int * list, ikincisi set farkını kullanır (boş set de sahtedir).

Çıktı formatı: Sıfır ve orta ve nihai puan endeksleri olarak verilen tüm optimal cevapların iç içe dizisi.

Örneğin: f([0,8,5,9,4,1,1,1,2,1,2]) == [[4, 8, 10, 12]].

Algoritma basit BFS'dir. daha önce ziyaret edilen endeksler hariç olmak üzere, yinelemedeki stüm olası iuzunluk yollarını kaydeder i. Tekrarlanan dizi erişimi pahalı olduğu için genişletilmiş yıldız gösteriminin (ab) kullanıldığını unutmayın. Böyle bir gösterimin doğru kullanıldığında bazı boşlukları da azaltabileceğini buldum.

Ayrıca yukarıdaki çözümden özyinelemeli (ancak daha uzun) bir sürüm yaptım. Hem s andve or sihtiyaç vardır, aksi takdirde çalışmaz.

Python 3 , 210 bayt

lambda a:[b[1:]for b in g(a,[[len(a)//2]],{len(a)//2})if not-1<b[-1]<len(a)]
g=lambda a,s,x:s and all(-1<b<len(a)for*c,b in s)and g(a,[x.add(u)or c+[b,u]for*c,b in s for u in[b+a[b],b-a[b]]if u not in x],x)or s

Çevrimiçi deneyin!


2

Haskell , 207 bayt

BMO sayesinde 5 bayt tasarruf etti .

l=length
x!p|i<-h p,d<-x!!i=[p++[x]|x<-[(-d,i-d),(d,i+d)],x`notElem`p]
x?p|i<-h p=i<0||i>=l x
h=snd.last
x#[]=[]
x#p|l(x%p)<1=x#(p>>=(x!))|1>0=x%p
(%)=filter.(?)
f x=(tail.map fst)<$>x#[[(0,l x`div`2)]]

Çevrimiçi deneyin!

Bu, aşağıdakilerin listesini alan bir işlevdir: Int parametre olarak bir listesini alan ve her yolun diziden çıkmak için alınan göreli sıçramaların bir listesi olduğu yolların listesini döndüren .

Çözülmemiş versiyon:

move :: [Int] -> [(Int, Int)] -> [Path]
move xs path = map(\x->path++[x]) $ filter (\s -> s`notElem`path) $ [(-delta, i-delta), (delta, i+delta)]
  where (_,i) = last path
        delta = xs!!i :: Int

outside :: [Int] -> Path -> Bool
outside xs paths = i < 0 || i >= length xs
  where (_,i) = last paths

shortest' :: [Path] -> [Int] -> [Path]
shortest' paths xs | null paths       = []
                   | not (null ready) = ready
                   | otherwise        = shortest' paths' xs
                   where ready  = filter (outside xs) paths
                         paths' = concatMap (move xs) paths

shortest xs = map tail $ map (map fst) $ shortest' [[(0,length xs`div`2)]] xs

2

C (gcc) , 269 bayt

#define A n){for(printf("%d,",n);i^l[i];i=l[i])printf("%d,",x[i]);break;}if(!u[n]){u[n]=x[m]=n;l[m++]=i;
#define M calloc(r,sizeof(s))
*x,*u,*l,s,m=1,i,j,n,w;main(r,v)char**v;{s=r-1;x=M;u=M;l=M;for(*x=1+s/2;i<m;i++){j=x[i];if(w=atoi(v[j])){n=j+w;if(s<A}n=j-w;if(1>A}}}}

Çevrimiçi deneyin!

Başlangıçta özyinelemeli bir geri izleme araması denedi, çünkü mainözyineleme için kullanmak her zaman eğlencelidir. Sonunda, basit bir özyinelemeli olmayan genişlik ilk arama daha küçük yapılabilirdi, bu sürüm budur. Bu program, girdi dizisini komut satırı bağımsız değişkenleri olarak alır, parantez içermez, örneğin 0 8 5 9 4 1 1 1 2 1 2ilk sağlanan örnek için. Program stdout çıktıları bir ifade listesi , nihai, sınırların dışında / 'kaçmış' dizininden başlayarak ve ulaşılan ara dizinler üzerinden geriye doğru çalışarak 1 dizinli , virgülle ayrılmış dizi indekslerinin ters sırayla çıkarır (çıktı vermez) merkezi, başlangıç ​​dizini). Program dizi etrafında kaşlı ayraçlar vermez ve ayrı bir virgül bırakırprintfifadeleri çok fazla karakter alır. Yukarıdaki ilk test örneğine karşılık gelen çıktı 13,11,9,5,, örneğin.

Dizi labirentinden kaçış yolu yoksa, program hiçbir şey vermez.

Degolfed ve aşağıda olduğunu açıkladı (okunabilirlik için bazı değişikliklerle ağır degolfed):

int *x, *u, *l, s, m = 1, i, j, n, w;                        //Declare all the state we'll need
int main(r, v) char** v;{                            
    s = r - 1;                                               //s is our actual array size, since v[0] is the program name.
    x = calloc(r, sizeof(int));                              //x is an array that will form our BFS queue. Since it is a BFS we've no need to visit any elements more than once (first visit will have been on a shortest route to it), so the amount of space we have here should suffice.
    u = calloc(r, sizeof(int));                              //u is an array that will be used to flag when an array index has been visited; only reason it's int* is for ease of declaration
    l = calloc(r, sizeof(int));                              //l is an array that will be used parallel to x and stores backpointers in the form of indexes into x, which will be used to construct the actual path once it is found.
    x[0] = 1 + (s/2);                                        //Init the first element in the queue to our center index of the array, adding one because of the program name in v/argv.
    for(; i < m; i++) {                                      //m is the number of elements in our BFS queue. It starts at 1 and grows during iteration; if this loop terminates before finding a path there is none.
        j = x[i];                                            //Current index in the array we are examining
        if (w = atoi(v[j])) {                                //Set w to be the actual array value at the current index (and check that it's nonzero since if it isn't we can't get anywhere from here)
            n = j + w;                                       //Try a move in the positive direction
            if (n > s) {                                     //If the move escapes the array
                for(printf("%d,", n); i ^ l[i]; i = l[i]) {  //Print the location escaped to and then loop back through the backpointers to reconstruct the path. The only backpointer that will point to its own queue index is the starting one, so terminate there.
                    printf("%d,", x[i]);                     //Print each intermediate array index
                }
                break;                                       //Then break the outer for loop and exit.
            }
            if(!u[n]) {                                      //If the jump didn't take us out of the array and we haven't visited where it goes to, add it to the queue.
                u[n] = x[m] = n;                             //m is the current tail of the queue, so put this new location there. Since we're 1-indexed and if n was zero we'd have escaped, we know it isn't so can use it to mark this index as visited also.
                l[m++] = i;                                  //Also set the backpointer for this new queue element to point back to the current index, then increment the tail of the queue.
            }
            n = j - w;                                       //Now the backwards move
            if (n < 1) {                                     //Repeat analogous to the forward case.
                for(printf("%d,", n); i ^ l[i]; i = l[i]) {
                    printf("%d,", x[i]);
                }
                break;
            }
            if (!u[n]) {
                u[n] = x[m] = n;
                l[m++] = i;
            }
        }
    }
}

Golf C kodu için her zamanki gibi, derleme çıktısı elbette dostça bir uyarı ve not duvarı içerecektir.



1

Perl 5 , -a: 73 bayt

(Eski stil sayımı: 75 bayt, +1için ave +1değiştirilmesi için -//tarafından -/$/kullanılarak $`için $')

#!/usr/bin/perl -a
use 5.10.0;
@;=$#F/2;$v{$^H=$_}//=push@;,map$'+$_*($F[$^H]//1/!say$').$".$',-//,1for@

Giriş dizisini STDIN'de bir satır olarak verin, ör. 0 8 5 9 4 1 1 1 2 1 2

ziyaret edilen konumları başlangıç ​​noktası da dahil olmak üzere ters sırada yazdırır, ardından çöker

Çözüm yoksa hiçbir şey yazdırmaz

Çevrimiçi deneyin!


1

Yakut , 102 bayt

->a{b=[[a.size>>1]];b.map{|x|(v=a[w=x[0]])&&w>=0?[w-v,w+v].map{|j|x.index(j)?0:b<<[j]+x}:(break p x)}}

Çevrimiçi deneyin!

Giriş labirentini bir dizi olarak alır, çıkıştan çıkış noktasına (dahil) çıkış yolunu tersine yazdırarak çıktı alır. Kaçış yoksa hiçbir şey yazdırmaz.

Bu yaklaşım, atılacak başka bir adım olduğunda sürekli olarak genişletilen yolların geçmişini saklayan geçici bir dizi boyunca yineleme yapmak için harita yöntemini yanlış kullanır.

Prensip olarak, return xyerine kullanarak başka bir bayt kaydedebilirim break p x, ama bu benim falsy değerimin depolanan tüm korkunç çöplere eşit olduğunu iddia etmek anlamına gelir b. Muhtemelen, bu, çıkışın izin verilen esnekliği düşünüldüğünde bile çok fazla olurdu ...

Bakış

->a{
  b=[[a.size>>1]] #Initialize an array of paths with our starting point index
  b.map{|x|       #Iterate through this array
    (v=a[w=x[0]]) #w is the current point in the path, v is its array value
    &&w>=0        #Ruby's support for negative indexing costs us 6 bytes :(
    ?             #If we are still within the bounds of the maze
      [w-v,w+v].map{|j| #Try moving in both directions
        x.index(j)? #If we have been there before, or stuck on zero
        0         #This is a dead-end, just assign a throwaway value
        :b<<[j]+x #Otherwise push the elongated path on top of our iterator
      } 
    :(break p x)  #Escaped! Exit the loop and report the path
  }  
}
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.