Mê cung mảng 1D


17

Lấy cảm hứng từ Chúng tôi nhảy tháp và liên quan đến Mê cung 2D Minus 1D

Giới thiệu

Nhiệm vụ của bạn là tìm ra con đường ngắn nhất để thoát khỏi một mê cung mảng theo các quy tắc được chỉ định.

Thử thách

Mảng 1D a với n phần tử có thể được coi là một mê cung gồm n điểm, trong đó điểm có chỉ số k được kết nối với các điểm với k + a [ k ] và k - a [ k ] theo cách một chiều. Nói cách khác, bạn có thể nhảy tiến hoặc lùi chính xác một bước [ k ] từ điểm có chỉ số k . Các điểm có chỉ số nằm ngoài giới hạn của mảng được xem xét bên ngoài mê cung.

Để minh họa điều này, hãy xem xét các mảng sau,

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

Nếu chúng ta đang ở phần tử thứ 5 ngay bây giờ, vì phần tử là 4, chúng ta có thể nhảy 4 bước về phía phần tử thứ 9 hoặc lùi 4 bước cho phần tử thứ 1. Nếu chúng ta thực hiện sau, chúng ta sẽ kết thúc với phần tử 0, điều này cho thấy không có động thái nào nữa. Nếu chúng ta làm trước, vì phần tử thứ 9 là 2, chúng ta có thể chọn chuyển sang phần tử thứ 11, lại là phần 2, và sau đó chúng ta có thể nhảy lại phần tử thứ 13, nằm ngoài giới hạn của phần tử thứ 13 mảng và được coi là một lối thoát vào mê cung.

Vì vậy, nếu chúng ta bắt đầu từ phần tử ở giữa, một cách để thoát khỏi mê cung là nhảy lùi 1 bước, tiến 4 bước, tiến 2 bước và lại 2 bước tiến, có thể được biểu thị dưới dạng mảng [-1,4,2,2]. Ngoài ra, bạn có thể biểu thị nó bằng mảng [4,8,10,12]ghi chỉ số dựa trên số không của tất cả các điểm trung gian và điểm cuối (chỉ số dựa trên 1 cũng tốt) hoặc chỉ các dấu hiệu , [-1,1,1,1].

Thoát khỏi mê cung từ đầu chỉ số thấp cũng OK.

Sử dụng ký hiệu đầu tiên và bắt đầu từ cùng một yếu tố, [1,1,1,2,2]cũng là một giải pháp nhưng nó không tối ưu vì có 5 bước thay vì 4.

Nhiệm vụ là tìm ra con đường ngắn nhất để thoát khỏi mê cung mảng và xuất ra đường dẫn. Nếu có nhiều hơn một đường dẫn tối ưu, bạn có thể xuất bất kỳ hoặc tất cả các đường dẫn đó. Nếu không có giải pháp, bạn nên xuất ra một giá trị giả do bạn chọn mà có thể thấy rõ từ một đường dẫn hợp lệ (không tạo ra đầu ra nào cả cũng được).

Để đơn giản, số phần tử trong mảng luôn là số lẻ và chúng tôi luôn bắt đầu từ phần tử ở giữa.

Các trường hợp thử nghiệm

Các trường hợp thử nghiệm minh họa các hình thức đầu ra khác nhau, nhưng bạn không bị giới hạn ở những trường hợp này.

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

Thông số kỹ thuật

  • Bạn có thể viết một chức năng hoặc một chương trình đầy đủ.

  • Mảng chỉ chứa các số nguyên không âm.

  • Bạn có thể nhận đầu vào và đầu ra thông qua bất kỳ hình thức tiêu chuẩn nào , nhưng vui lòng ghi rõ trong câu trả lời của bạn về hình thức bạn đang sử dụng.

  • Đây là , số byte thấp nhất sẽ thắng.

  • Như thường lệ, sơ hở mặc định áp dụng ở đây.


Có ổn không khi xuất ra một mảng lồng nhau ngay cả khi câu trả lời là duy nhất? (ví dụ: [0,8,5,9,4,1,1,1,2,1,2]xuất ra [[-1,4,2,2]])
Bubbler

@Bubbler Có, bạn có thể xuất mảng lồng nhau.
Weijun Zhou

Có thể trả lại lối thoát theo thứ tự ngược lại. Vậy [1,1,1,-1]thay vì [-1,1,1,1]?
TonMedel

@TonH rửa Có, chỉ cần nói như vậy trong câu trả lời của bạn.
Weijun Zhou

trường hợp thử nghiệm 2 có vẻ không chính xác, bạn có thể giải thích nó?
edc65

Câu trả lời:


3

JavaScript (ES6), 117 byte

Trả về một mảng gồm các điểm trung gian và điểm cuối được lập chỉ mục 0 hoặc một mảng trống nếu không có giải pháp nào tồn tại.

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

Hãy thử trực tuyến!

Đã bình luận

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

Husk , 22 byte

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

Trả về danh sách các dấu hiệu hoặc danh sách trống nếu giải pháp không tồn tại. Hãy thử trực tuyến!

Giải trình

Đây là một giải pháp vũ phu kiểm tra danh sách theo -1,0,1chiều dài tăng dần và trả về giải pháp đầu tiên dẫn đến việc nhảy ra khỏi mảng. Vì nó có độ dài tối thiểu, nó sẽ không chứa 0s.

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

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]

Hãy thử trực tuyến!

Biên tập:

  • Lưu 9 byte bằng all(..)and s => all(..)*s, if u not in x => if{u}-x
    Chiến công cựu boolean * list == int * list, sự khác biệt sử dụng sau set (tập rỗng cũng là falsy).

Định dạng đầu ra: Mảng lồng nhau của tất cả các câu trả lời tối ưu, được đưa ra dưới dạng chỉ số dựa trên điểm 0 của điểm trung gian và điểm cuối.

Ví dụ : f([0,8,5,9,4,1,1,1,2,1,2]) == [[4, 8, 10, 12]].

Thuật toán là BFS đơn giản. sghi lại tất cả các iđường dẫn có thể có trong ilần lặp lại, ngoại trừ các chỉ mục đã được truy cập. Lưu ý rằng ký hiệu sao mở rộng là (ab) được sử dụng vì truy cập mảng lặp lại rất tốn kém. Tôi thấy rằng một ký hiệu như vậy cũng có thể làm giảm một số khoảng trắng nếu được sử dụng đúng cách.

Tôi cũng đã thực hiện một phiên bản đệ quy (nhưng dài hơn) trong số các giải pháp trên. Cả hai s andor sđều cần thiết, nếu không nó không hoạt động.

Python 3 , 210 byte

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

Hãy thử trực tuyến!


2

Haskell , 207 202 byte

5 byte được lưu nhờ BMO .

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

Hãy thử trực tuyến!

Đây là một hàm lấy danh sách Intlàm tham số và trả về danh sách các đường dẫn trong đó mỗi đường dẫn là một danh sách các bước nhảy tương đối được thực hiện để thoát khỏi mảng.

Phiên bản chưa được chỉnh sửa:

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 byte

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

Hãy thử trực tuyến!

Ban đầu đã thử tìm kiếm quay lui đệ quy, bởi vì sử dụng maincho đệ quy luôn luôn thú vị. Cuối cùng, mặc dù một tìm kiếm đầu tiên không đệ quy đơn giản có thể được thực hiện nhỏ hơn, đó là phiên bản này. Chương trình này lấy mảng đầu vào làm đối số dòng lệnh, không có dấu ngoặc, ví dụ 0 8 5 9 4 1 1 1 2 1 2cho ví dụ được cung cấp đầu tiên. Các đầu ra chương trình trên stdout danh sách 1-lập chỉ mục , dấu phẩy phân cách chỉ số mảng theo thứ tự ngược, bắt đầu từ trận chung kết, out-of-bounds / 'thoát' chỉ mục và trở lại làm việc thông qua các chỉ số trung gian đạt (nó không sản lượng trung tâm, chỉ số bắt đầu). Chương trình không xuất ra dấu ngoặc nhọn xung quanh mảng và để lại dấu phẩy vì tách biệtprintfbáo cáo mất rất nhiều nhân vật. Đầu ra tương ứng với ví dụ thử nghiệm đầu tiên ở trên là 13,11,9,5,, ví dụ.

Nếu không có lối thoát khỏi mê cung mảng, chương trình không xuất ra bất cứ thứ gì.

Đã bị khử và giải thích nó ở bên dưới (bị biến dạng nặng nề với một số thay đổi về khả năng đọc):

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

Như thường lệ đối với mã C được đánh gôn, đầu ra biên dịch tất nhiên sẽ bao gồm một bức tường cảnh báo và ghi chú thân thiện.



1

Perl 5 , -a: 73 byte

(đếm kiểu cũ: 75 byte, +1cho a+1thay thế -//bằng -/$/và sử dụng $`cho $')

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

Đưa ra mảng đầu vào dưới dạng một dòng trên STDIN, vd 0 8 5 9 4 1 1 1 2 1 2

in các vị trí đã truy cập theo thứ tự ngược bao gồm điểm bắt đầu, sau đó gặp sự cố

Không in gì nếu không có giải pháp

Hãy thử trực tuyến!


1

Ruby , 102 byte

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

Hãy thử trực tuyến!

Lấy mê cung đầu vào dưới dạng một mảng, xuất ra bằng cách in đường thoát ngược lại, từ lối ra đến điểm bắt đầu (đã bao gồm). Không in gì nếu không có lối thoát.

Cách tiếp cận này sử dụng sai phương thức bản đồ để lặp qua một mảng tạm thời lưu trữ lịch sử của các đường dẫn, liên tục được mở rộng bất cứ khi nào có một bước khả thi khác.

Về nguyên tắc, tôi có thể lưu một byte khác bằng cách sử dụng return xthay vì break p x, nhưng điều đó có nghĩa là tuyên bố rằng giá trị giả của tôi bằng với tất cả rác rưởi quái dị được lưu trữ trong đó b. Có lẽ, điều này sẽ là quá nhiều, thậm chí xem xét tính linh hoạt được phép của đầu ra ...

Hướng dẫn

->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
  }  
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.