1D 호핑 배열 미로


17

에서 영감을 우리는 타워 도약을 하고 관련 2D 미로 마이너스 1D

소개

당신의 임무는 지정된 규칙에 따라 배열 미로에서 벗어날 수있는 가장 짧은 경로를 찾는 것입니다.

도전

n 개의 요소를 갖는 1D 어레이 an 개의 포인트 로 구성된 미로로 간주 될 수 있으며 , 여기서 인덱스 k 를 갖는 포인트는 일방향 방식으로 k + a [ k ] 및 k - a [ k ]를 갖는 포인트에 연결된다 . 즉, 앞으로 또는 뒤로 정확하게 이동할 수 있습니다 [ K 지수와 지점에서] 단계 K . 배열의 경계를 벗어난 인덱스를 가진 포인트는 미로 외부에서 간주됩니다.

이를 설명하기 위해 다음 배열을 고려하십시오.

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

현재 5 번째 요소 인 경우 요소가 4이므로 4 단계를 9 번째 요소로, 또는 4 단계를 1 번째 요소로 홉할 수 있습니다. 후자를 수행하면 요소 0으로 끝나고 더 이상 이동할 수 없음을 나타냅니다. 전자를 수행하면 9 번째 요소가 2이므로 11 번째 요소 (두 번째 요소)로 홉하도록 선택할 수 있으며, "13 번째 요소"로 다시 홉할 수 있습니다. 배열과 미로의 출구를 고려했다.

따라서 중간에있는 요소에서 시작하면 미로에서 나가는 한 가지 방법은 1 단계 뒤로, 4 단계 앞으로, 2 단계 앞으로, 2 단계 앞으로 이동하는 것 [-1,4,2,2]입니다. 이는 배열로 표현할 수 있습니다 . 또는 [4,8,10,12]모든 중간 및 최종 포인트의 0부터 시작하는 인덱스 (1부터 시작하는 인덱스도 좋음) 또는 부호 만 기록 하는 배열로 이를 표현할 수 있습니다 [-1,1,1,1].

낮은 인덱스 끝에서 미로를 탈출하는 것도 좋습니다.

첫 번째 표기법을 사용하고 동일한 요소에서 시작하는 [1,1,1,2,2]것도 해결책이지만 4 단계 대신 5 단계가 있기 때문에 최적이 아닙니다.

임무는 배열 미로에서 빠져 나와 경로를 출력하는 가장 짧은 경로를 찾는 것입니다. 최적 경로가 두 개 이상인 경우 일부 또는 전부를 출력 할 수 있습니다. 솔루션이없는 경우 올바른 경로에서 식별 할 수있는 잘못된 값을 출력해야합니다 (아무 출력도 생성되지 않음).

간단히하기 위해 배열의 요소 수는 항상 홀수이며 중간 요소부터 시작합니다.

테스트 사례

테스트 사례는 다양한 형태의 출력을 보여 주지만 이에 국한되지는 않습니다.

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

명세서

  • 함수 또는 전체 프로그램을 작성할 수 있습니다.

  • 배열은 음이 아닌 정수만 포함합니다.

  • 모든 표준 양식을 통해 입력 및 출력을 수행 할 수 있지만 사용중인 양식을 응답으로 지정하십시오.

  • 이것은 가장 적은 바이트 수의이기는 입니다.

  • 평소와 같이 기본 허점 이 여기에 적용됩니다.


답이 고유하더라도 중첩 배열을 출력하는 것이 좋습니까? (예 : [0,8,5,9,4,1,1,1,2,1,2]출력 [[-1,4,2,2]])
Bubbler

@Bubbler 네, 중첩 배열을 출력 할 수 있습니다.
Weijun Zhou

이스케이프 경로를 역순으로 반환해도됩니다. 그래서 [1,1,1,-1]대신에 [-1,1,1,1]?
Ton Hospel

@TonHospel 예, 답을 말씀해주십시오.
Weijun Zhou

테스트 사례 2가 잘못된 것 같습니다. 설명해 주시겠습니까?
edc65

답변:


3

자바 스크립트 (ES6), 117 바이트

인덱스가 0 인 중간 및 최종 점의 배열을 반환하거나 솔루션이없는 경우 빈 배열을 반환합니다.

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

온라인으로 사용해보십시오!

댓글

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

껍질 , 22 바이트

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

솔루션이없는 경우 기호 목록 또는 빈 목록을 반환합니다. 온라인으로 사용해보십시오!

설명

이 방법은 길이가 길어짐 -1,0,1에 따라 목록을 확인 하고 첫 번째 항목을 반환하여 결과를 뛰어 넘는 무차별 대입 솔루션입니다 . 최소 길이이므로 0을 포함하지 않습니다.

ḟȯ¬€ŀ¹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

파이썬 3 , 195 188 179 바이트

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]

온라인으로 사용해보십시오!

편집하다:

  • 선방 9 바이트 all(..)and s => all(..)*s, if u not in x => if{u}-x
    전자 공격boolean * list == int * list 하고 후자는 세트 차이를 사용합니다 (빈 세트도 거짓).

출력 형식 : 중간 및 최종 포인트의 0부터 시작하는 인덱스로 제공되는 모든 최적 답변의 중첩 배열입니다.

예를 들면 다음과 같습니다. f([0,8,5,9,4,1,1,1,2,1,2]) == [[4, 8, 10, 12]] ..

알고리즘은 간단한 BFS입니다. s가능한 모든 i길이 경로를 기록합니다 .i이미 방문한 인덱스를 제외하고 반복 . 반복 된 배열 액세스는 비용이 많이 들기 때문에 확장 된 별표 표기법은 (ab) 사용됩니다. 이러한 표기법은 올바르게 사용하면 일부 공백을 줄일 수 있다는 것을 알았습니다.

또한 위의 솔루션에서 재귀 적이지만 더 긴 버전을 만들었습니다. 모두 s andor s필요, 그렇지 않으면 작동하지 않습니다.

파이썬 3 , 210 바이트

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

온라인으로 사용해보십시오!


2

하스켈 , 207202 바이트

BMO 덕분에 5 바이트가 절약되었습니다 .

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

온라인으로 사용해보십시오!

이것은 목록을 취하는 기능입니다 Int 매개 변수로 각 경로가 배열에서 나가기위한 상대 점프 목록 인 경로 목록을 리턴 .

언 골프 버전 :

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 바이트

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

온라인으로 사용해보십시오!

재귀에 사용 main하는 것이 항상 재미 있기 때문에 처음에는 재귀 역 추적 검색을 시도했습니다 . 결국 간단한 비 재귀 너비 우선 검색을 더 작게 만들 수 있었지만 이것이 바로이 버전입니다. 이 프로그램은 입력 배열을 중괄호없이 명령 줄 인수로 사용합니다 (예 : 0 8 5 9 4 1 1 1 2 1 2첫 번째 제공된 예). 프로그램은 stdout에서 목록에 1- 인덱싱 된 , 쉼표로 구분 된 배열 인덱스 목록을 역순으로 출력합니다. 최종의 범위를 벗어난 / '이스케이프 된'인덱스에서 시작하여 도달 한 중간 인덱스를 통해 다시 작동합니다 (출력하지 않습니다). 중심, 시작 색인). 프로그램은 배열 주위에 중괄호를 출력하지 않으며 별도의 때문에 후행 쉼표를 남깁니다.printf문장은 많은 문자를 취합니다. 상기 제 1 시험 예에 대응하는 출력 13,11,9,5,은 예를 들어이다.

배열 미로에서 이스케이프 경로가 없으면 프로그램이 아무것도 출력하지 않습니다.

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

골프 C 코드의 경우와 마찬가지로 컴파일 출력에는 물론 친절한 경고 및 메모가 포함됩니다.



1

Perl 5 , -a : 73 바이트

(이전 스타일 계산 : 75 바이트 +1에 대한 a+1교체 -//에 의해 -/$/및 사용 $`에 대한 $')

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

STDIN에서 입력 배열을 한 줄로 지정하십시오. 0 8 5 9 4 1 1 1 2 1 2

시작 지점을 포함하여 방문한 위치를 역순으로 인쇄 한 다음 충돌

해결책이 없으면 아무것도 인쇄하지 않습니다

온라인으로 사용해보십시오!


1

루비 , 102 바이트

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

온라인으로 사용해보십시오!

입력 미로를 배열로 취하고, 탈출 점을 시작점 (포함)으로 역으로 이스케이프 경로를 인쇄하여 출력합니다. 이스케이프가 없으면 아무것도 인쇄하지 않습니다.

이 방법은 경로 기록을 저장하는 임시 배열을 반복하기 위해 맵 방법을 잘못 사용하며, 가능한 다른 단계가있을 때마다 계속 확장됩니다.

원칙적으로, return x대신을 사용하여 다른 바이트를 절약 할 수 는 break p x있지만, 잘못된 값은에 저장된 모든 괴물 같은 쓰레기와 같다고 주장합니다 b. 아마도 이것은 출력의 허용 된 유연성을 고려하더라도 너무 많을 것입니다 ...

연습

->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
  }  
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.