Đường dẫn tối ưu thông qua ma trận


19

Cho một ma trận bao gồm các số nguyên dương, xuất đường dẫn có tổng thấp nhất khi di chuyển từ phần tử phía trên bên trái sang phía dưới bên phải. Bạn có thể di chuyển theo chiều dọc, chiều ngang và đường chéo. Lưu ý rằng có thể di chuyển cả lên / xuống, phải / trái và chéo sang tất cả các bên.

Thí dụ:

 1*   9    7    3   10    2    2
10    4*   1*   1*   1*   7    8
 3    6    3    8    9    5*   7
 8   10    2    5    2    1*   4
 5    1    1    3    6    7    9*

Đường dẫn cho tổng thấp nhất được đánh dấu bằng dấu hoa thị và kết quả là tổng sau: 1 + 4 + 1 + 1 + 1 + 5 + 1 + 9 = 23 .

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

1   1   1
1   1   1
Output: 3

 7    9    6    6    4
 6    5    9    1    6
10    7   10    4    3
 4    2    2    3    7
 9    2    7    9    4
Output: 28

2  42   6   4   1
3  33   1   1   1
4  21   7  59   1
1   7   6  49   1
1   9   2  39   1
Output: 27 (2+3+4+7+7+1+1+1+1)

 5    6    7    4    4
12   12   25   25   25
 9    4   25    9    5
 7    4   25    1   12
 4    4    4    4    4
Output: 34 (5+12+4+4+4+1+4)

1   1   1   1
9   9   9   1
1   9   9   9
1   9   9   9
1   1   1   1
Output: 15

 2   55    5    3    1    1    4    1
 2   56    1   99   99   99   99    5
 3   57    5    2    2    2   99    1
 3   58    4    2    8    1   99    2
 4   65   66   67   68    3   99    3
 2    5    4    3    3    4   99    5
75   76   77   78   79   80   81    2
 5    4    5    1    1    3    3    2
Output: 67 (2+2+3+3+4+5+4+3+3+3+1+2+2+1+3+1+1+4+5+1+2+3+5+2+2)

Đây là nên mã ngắn nhất trong mỗi ngôn ngữ sẽ thắng.


Rất giống nhau , mặc dù nó không cho phép di chuyển chéo.
Mego

7
@WheatWizard Tôi không đồng ý. Ngoài những khác biệt chủ yếu là bề ngoài mà thử thách này cho phép di chuyển chéo và tất cả các vị trí đều có thể tiếp cận được, thử thách khác đòi hỏi phải trả lại chính con đường thay vì chỉ chi phí của đường dẫn. Trừ khi bạn đang sử dụng các phần tử tích hợp trả về cả hai, mã không thể thay thế cho nhau.
cốc

@beaker Tôi không thực sự thấy sự khác biệt. Bạn phải tìm đường dẫn để biết chiều dài của nó. Sự khác biệt ở đây là một sự khác biệt khá nhỏ về đầu ra theo ý kiến ​​của tôi và thử thách này không mang lại điều gì mới mẻ hay thú vị chưa được bao phủ bởi thử thách đó.
Thuật sĩ lúa mì

1
@WheatWizard Giải pháp của tôi ở đây không tìm thấy đường dẫn. Nó có thể tìm thấy đường dẫn, nhưng không phải không có một mảng và logic tiền thân riêng biệt để tránh tạo một nút tiền thân của nó. Không đề cập đến việc phục hồi con đường ở cuối.
cốc

@beaker Việc sửa đổi là khá tầm thường theo quan điểm của tôi. Bất kể câu hỏi về bản sao không phải là liệu mọi mục nhập hợp lệ trong một thử thách có thể được chuyển qua với nỗ lực tối thiểu hay không, đó là về trường hợp chung. Tôi không chỉ nghĩ rằng hầu hết các nỗ lực ở đây đều có thể được chuyển. Tôi không nghĩ thử thách này mang lại điều gì mới mẻ hay thú vị từ bên kia.
Thuật sĩ lúa mì

Câu trả lời:


8

JavaScript, 438 412 408 358 byte

Đây là lần nộp PPCG đầu tiên của tôi. Phản hồi sẽ được đánh giá cao.

(m,h=m.length,w=m[0].length)=>{for(i=0;i<h*w;i++)for(x=0;x<w;x++){for(y=0;y<h;y++){if(m[y][x]%1==0)m[y][x]={c:m[y][x],t:m[y][x]};for(X=-1;X<=1;X++)for(Y=-1;Y<=1;Y++){t=x+X;v=y+Y;if((X==0&&Y==0)||t<0||t>=w||v<0||v>=h)continue;if(m[v][t]%1==0)m[v][t]={c:m[v][t],t:null};c=m[y][x].t+m[v][t].c;if (c<m[v][t].t||m[v][t].t==null)m[v][t].t=c}}}return m[h-1][w-1].t}

Điều này có một mảng đa chiều làm đầu vào.

Giải trình

Về cơ bản, lặp qua tất cả các ô liên tục để điều chỉnh chi phí thấp nhất được biết đến để đến từng hàng xóm. Cuối cùng, lưới sẽ đạt đến trạng thái trong đó tổng chi phí để chạm đáy phải là chi phí thấp nhất để đạt được điều đó.

Bản giới thiệu

f=(m,h=m.length,w=m[0].length)=>{for(i=0;i<h*w;i++)for(x=0;x<w;x++){for(y=0;y<h;y++){if(m[y][x]%1==0)m[y][x]={c:m[y][x],t:m[y][x]};for(X=-1;X<=1;X++)for(Y=-1;Y<=1;Y++){t=x+X;v=y+Y;if((X==0&&Y==0)||t<0||t>=w||v<0||v>=h)continue;if(m[v][t]%1==0)m[v][t]={c:m[v][t],t:null};c=m[y][x].t+m[v][t].c;if (c<m[v][t].t||m[v][t].t==null)m[v][t].t=c}}}return m[h-1][w-1].t}

//Tests
console.log(f([[1,1,1],[1,1,1]])===3);
console.log(f([[7,9,6,6,4],[6,5,9,1,6],[10,7,10,4,3],[4,2,2,3,7],[9,2,7,9,4]])===28);
console.log(f([[2,42,6,4,1],[3,33,1,1,1],[4,21,7,59,1],[1,7,6,49,1],[1,9,2,39,1]])===27);
console.log(f([[5,6,7,4,4],[12,12,25,25,25],[9,4,25,9,5],[7,4,25,1,12],[4,4,4,4,4]])===34); 
console.log(f([[1,1,1,1],[9,9,9,1],[1,9,9,9],[1,9,9,9],[1,1,1,1]])===15)
console.log(f([[2,55,5,3,1,1,4,1],[2,56,1,99,99,99,99,5],[3,57,5,2,2,2,99,1],[3,58,4,2,8,1,99,2],[4,65,66,67,68,3,99,3],[2,5,4,3,3,4,99,5],[75,76,77,78,79,80,81,2],[5,4,5,1,1,3,3,2]])===67);

Chỉnh sửa: Đặc biệt cảm ơn @ETHproductions đã giúp tôi cạo hàng chục byte ngon.

Cảm ơn nhiều hơn đến @Stewie Griffin vì những lời khuyên của bạn đã loại bỏ 50 byte.


3
Chào mừng đến với PPCG! Có một số khoảng trắng bổ sung mà bạn có thể xóa vào cuối (tôi đếm tổng cộng 5) và bạn không cần bất kỳ dấu chấm phẩy nào trực tiếp trước khi }cần lưu một vài byte. Bạn cũng không cần phải khai báo các biến của mình; Tôi nghĩ rằng việc loại bỏ các vars sẽ giúp bạn tiết kiệm tổng cộng 24 byte.
Sản xuất ETH

2
Chào mừng bạn đến với PPCG =) Tôi rất vui vì bạn đã chọn một trong những thử thách của tôi làm điểm khởi đầu. Nhận xét duy nhất của tôi: Tôi thích giải thích. Mặc dù đó là tùy chọn, vì vậy bạn không cần phải thêm nó trừ khi bạn muốn. :)
Stewie Griffin

Tôi nghĩ có thể lưu trữ m[v][t]dưới dạng một biến: t=x+X;v=y+Y;k=m[v][t]sẽ còn ngắn hơn nữa ...?
Stewie Griffin


6

Gói Octave + Xử lý hình ảnh, 175 162 157 151 142 139 byte

Đã lưu 14 byte nhờ @Luis Mendo và 1 byte nhờ @notjagan

function P(G)A=inf(z=size(G));A(1)=G(1);for k=G(:)'B=im2col(padarray(A,[1,1],inf),[3,3])+G(:)';B(5,:)-=G(:)';A=reshape(min(B),z);end,A(end)

Sử dụng gói Xử lý hình ảnh, tại sao không? Không phải đó là cách mọi người giải quyết vấn đề đồ thị sao?

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

Phát nổ

function P(G)
   A=inf(z=size(G));         % Initialize distance array to all Inf
   A(1)=G(1);                % Make A(1) = cost of start cell
   for k=G(:)'               % For a really long time...
      B=im2col(padarray(A,[1,1],inf),[3,3])+G(:)';
       %  B=padarray(A,[1,1],inf);     % Add border of Inf around distance array
       %  B=im2col(B,[3,3]);           % Turn each 3x3 neighborhood into a column
       %  B=B+G(:)';                   % Add the weights to each row
      B(5,:)-=G(:)';         % Subtract the weights from center of neighborhood
      A=reshape(min(B),z);   % Take minimum columnwise and reshape to original
   end
   A(end)                    % Display cost of getting to last cell

Giải trình

Đưa ra một loạt các trọng số:

7   12    6    2    4
5   13    3   11    1
4    7    2    9    3
4    2   12   13    4
9    2    7    9    4

Khởi tạo một mảng chi phí sao cho chi phí để đạt được mọi phần tử là Vô cực, ngoại trừ điểm bắt đầu (phần tử phía trên bên trái) có chi phí bằng trọng lượng của nó.

  7   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf

Đây là lần lặp 0. Đối với mỗi lần lặp tiếp theo, chi phí để đạt được một ô được đặt ở mức tối thiểu là:

  • chi phí hiện tại để đạt được yếu tố đó và
  • chi phí hiện tại để tiếp cận hàng xóm của phần tử + trọng lượng của phần tử

Sau lần lặp đầu tiên, chi phí của đường dẫn đến phần tử (2,2) (sử dụng lập chỉ mục dựa trên 1) sẽ là

minimum([  7   Inf   Inf]   [13  13  13]) = 20
        [Inf   Inf   Inf] + [13   0  13]
        [Inf   Inf   Inf]   [13  13  13]

Mảng chi phí đầy đủ sau lần lặp đầu tiên sẽ là:

  7    19   Inf   Inf   Inf
 12    20   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf

Sau khi lặp lại k, mỗi phần tử sẽ là chi phí thấp nhất để đạt được phần tử đó ngay từ đầu bắt đầu ở hầu hết kcác bước. Ví dụ: phần tử tại (3,3) có thể đạt được trong 2 bước (lặp) với chi phí 22:

  7    19    25   Inf   Inf
 12    20    22   Inf   Inf
 16    19    22   Inf   Inf
Inf   Inf   Inf   Inf   Inf
Inf   Inf   Inf   Inf   Inf

Nhưng ở lần lặp thứ 4, một đường dẫn gồm 4 bước được tìm thấy với chi phí là 20:

 7   19   25   24   28
12   20   22   32   25
16   19   20   30   34
20   18   30   34   35
27   20   25   40   39

Vì không có đường dẫn nào qua ma trận mxn có thể dài hơn số phần tử trong ma trận (như một giới hạn trên rất lỏng lẻo), sau khi m*nlặp lại, mọi phần tử sẽ chứa chi phí của con đường ngắn nhất để tiếp cận phần tử đó từ đầu.


-1 byte bằng cách loại bỏ khoảng trắng giữa while~.
notjagan

@notjagan Tôi chuyển từ whilesang forvà vẫn có thể sử dụng mẹo của bạn. Cảm ơn!
cốc

5

JavaScript, 197 byte

a=>(v=a.map(x=>x.map(_=>1/0)),v[0][0]=a[0][0],q=[...(a+'')].map(_=>v=v.map((l,y)=>l.map((c,x)=>Math.min(c,...[...'012345678'].map(c=>a[y][x]+((v[y+(c/3|0)-1]||[])[x+c%3-1]||1/0)))))),v.pop().pop())

Làm đẹp

a=>(
  // v is a matrix holds minimal distance to the left top
  v=a.map(x=>x.map(_=>1/0)),
  v[0][0]=a[0][0],
  q=[
     // iterate more than width * height times to ensure the answer is correct
    ...(a+'')
  ].map(_=>
    v=v.map((l,y)=>
      l.map((c,x)=>
        // update each cell
        Math.min(c,...[...'012345678'].map(
          c=>a[y][x]+((v[y+(c/3|0)-1]||[])[x+c%3-1]||1/0)
        ))
      )
    )
  ),
  // get result at right bottom
  v.pop().pop()
)

4

Toán học 279 byte

Ý tưởng cơ bản là tạo một biểu đồ có các đỉnh tương ứng với các mục ma trận và các cạnh được định hướng giữa hai đỉnh bất kỳ cách nhau một khoảng ChessboardDistancelớn hơn 0 nhưng nhỏ hơn hoặc bằng 1. Vô tình, điều này xảy ra được gọi là biểu đồ King , vì nó tương ứng với các động thái hợp lệ của một vị vua trên bàn cờ.

FindShortestPathsau đó được sử dụng để có được đường dẫn tối thiểu. Nó hoạt động trên EdgeWeight, không VertexWeight, vì vậy có một số mã bổ sung để xác định EdgeWeightmục nhập ma trận tương ứng với đích của mỗi cạnh được định hướng.

Mã số:

(m=Flatten[#];d=Dimensions@#;s=Range[Times@@d];e=Select[Tuples[s,2],0<ChessboardDistance@@(#/.Thread[s->({Ceiling[#/d[[1]]],Mod[#,d[[1]],1]}&/@s)])≤1&];Tr[FindShortestPath[Graph[s,#[[1]]->#[[2]]&/@e,EdgeWeight->(Last@#&/@Map[Extract[m,#]&,e,{2}])],1,Last@s]/.Thread[s->m]])&

Lưu ý rằng ký tự là biểu tượng chuyển vị. Nó sẽ dán vào Mathicala như vốn có.

Sử dụng:

%@{{2, 55, 5, 3, 1, 1, 4, 1},
  {2, 56, 1, 99, 99, 99, 99, 5},
  {3, 57, 5, 2, 2, 2, 99, 1},
  {3, 58, 4, 2, 8, 1, 99, 2},
  {4, 65, 66, 67, 68, 3, 99, 3},
  {2, 5, 4, 3, 3, 4, 99, 5},
  {75, 76, 77, 78, 79, 80, 81, 2},
  {5, 4, 5, 1, 1, 3, 3, 2}}

Đầu ra:

67

Nếu bạn đặt g=Graph[...,GraphLayout->{"GridEmbedding","Dimension"->d},VertexLabels->Thread[s->m]p=FindShortestPath[...sau đó đồ họa sau sẽ hiển thị trực quan giải pháp (trên cùng của ma trận tương ứng với dưới cùng của biểu đồ):

HighlightGraph[g,PathGraph[p,Thread[Most@p->Rest@p]]]

nhập mô tả hình ảnh ở đây


3

Haskell, 228 byte

Vị trí là danh sách của hai yếu tố, bởi vì những vị trí này dễ tạo sequencevà chỉ dễ tạo mẫu khớp với 2-tuples.

h=g[[-1,-1]]
g t@(p:r)c|p==m=0|1<2=minimum$(sum$concat c):(\q@[a,b]->c!!a!!b+g(q:t)c)#(f(e$s$(\x->[0..x])#m)$f(not.e t)$zipWith(+)p#s[[-1..1],[-1..1]])where m=[l(c)-1,l(head c)-1]
(#)=map
f=filter
e=flip elem
s=sequence
l=length

Bắt đầu -1,-1và tính chi phí của từng bước đích trường.

Hai dòng đầu tiên thay thế: bắt đầu tại 0,0, đếm các trường khởi hành, chấm dứt tại các tọa độ bằng với kích thước ma trận (do đó, ngay bên phải từ mục tiêu, cần được thêm vào danh sách các điểm đến hợp pháp) - chính xác cùng độ dài nhưng chậm hơn:

j=i[[0,0]]
i t@(p@[a,b]:r)c|p==m=0|1<2=c!!a!!b+(minimum$(sum$concat c):(\q->i(q:t)c)#(f(e$m:(s$(\x->[0..x-1])#m))$f(not.e t)$zipWith(+)p#s[[-1..1],[-1..1]]))where m=[l c,l$head c]

Sử dụng một infix cho mapkhông tiết kiệm byte ở đây nhưng tôi thay thế nó ngay khi nó không tốn một khoản nào, bởi vì nó chỉ có thể trở nên tốt hơn với nhiều lần sử dụng hơn, và đôi khi với các cấu trúc lại khác cũng giúp loại bỏ một cặp dấu ngoặc khác.

Để được cải thiện: Dự phòng filters. Sáp nhập / in-xếp hàng họ filter(flip elem$(s$(\x->[0..x])#m)\\p)với import Data.Listcho \\chi phí 3 byte.

Ngoài ra, quá tệ (fromEnumTo 0)là 2 byte dài hơn (\x->[0..x]).

sum$concat clà tổng chi phí của tất cả các trường và do đó, giới hạn trên có thể biểu thị chính xác trên chi phí đường dẫn được đưa ra minimumđể tránh danh sách trống (trình kiểm tra loại của tôi đã xác định toàn bộ hoạt động trên Integers, do đó, không mã hóa tối đa , hehe). Cho dù tôi hạn chế các bước dựa trên bước trước đó như thế nào (điều này sẽ tăng tốc thuật toán lên rất nhiều, nhưng cũng tốn byte), tôi không thể tránh được những ngõ cụt khiến việc quay trở lại này trở nên cần thiết.

  • Một ý tưởng bộ lọc là ((not.e n).zipWith(-)(head r))với trích xuất n=s[[-1..1],[-1..1]], đòi hỏi phải thêm ,[-1,-1]vào đường dẫn ban đầu. Thuật toán sau đó tránh đi đến nơi mà nó có thể đã đi ở bước trước, điều này làm cho việc bước trên một trường cạnh trực giao với cạnh đó trở thành ngõ cụt.

  • Một cách khác là ((>=0).sum.z(*)d)trích xuất z=zipWith, trong đó đưa ra một đối số mới dcho hàm đệ quy được đưa ra như (z(-)p q)trong đệ quy và [1,1]trong trường hợp ban đầu. Thuật toán tránh các bước liên tiếp với một sản phẩm vô hướng âm ( dlà bước trước đó), có nghĩa là không có góc quay 45 ° sắc nét. Điều này vẫn thu hẹp đáng kể các lựa chọn và tránh được ngõ cụt tầm thường trước đó, nhưng vẫn có những con đường kết thúc trong các trường đã được truy cập (và có thể là một 'lối thoát', tuy nhiên sẽ là một bước ngoặt sắc nét).


3

Python 2, 356 320 byte

s=input()
r=lambda x:[x-1,x,x+1][-x-2:]
w=lambda z:[z+[(x,y)]for x in r(z[-1][0])for y in r(z[-1][1])if x<len(s)>0==((x,y)in z)<len(s[0])>y]
l=len(s)-1,len(s[0])-1
f=lambda x:all(l in y for y in x)and x or f([a for b in[l in z and[z]or w(z)for z in x]for a in b])
print min(sum(s[a][b]for(a,b)in x)for x in f([[(0,0)]]))

Hãy thử nó ở đây!

-36 byte nhờ notjagan !

Nhận danh sách các danh sách dưới dạng đầu vào và xuất chi phí thấp nhất khi điều hướng ma trận từ phía trên bên trái sang phía dưới bên phải.

Giải trình

Tìm mọi tuyến đường có thể từ phía trên bên trái đến dưới cùng bên phải của ma trận, tạo danh sách tọa độ x, y cho mỗi tuyến đường. Các tuyến đường không thể quay lại và chúng phải kết thúc tại (len(s)-1,len(s[0])-1).

Tính tổng các số nguyên trên mỗi đường tọa độ và trả lại chi phí tối thiểu.

printthể dễ dàng thay đổi để xuất danh sách tọa độ cho tuyến đường ngắn nhất.


-36 byte với một số thay đổi linh tinh.
notjagan

@notjagan Những thay đổi lớn, đặc biệt là việc sử dụng orcho các điều kiện. Cảm ơn bạn!
Giải quyết

1

APL (Dyalog Classic) , 33 byte

{⊃⌽,(⊢⌊⍵+(⍉3⌊/⊣/,⊢,⊢/)⍣2)⍣≡+\+⍀⍵}

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

{ } chức năng với đối số

+\+⍀⍵ lấy một phần tiền theo hàng và theo cột để thiết lập giới hạn bi quan trên khoảng cách đường dẫn

( )⍣≡ lặp lại cho đến khi hội tụ:

  • (⍉3⌊/⊣/,⊢,⊢/)⍣2tối thiểu khoảng cách đến các hàng xóm, tức là thực hiện hai lần ( ( )⍣2): thêm cột ngoài cùng bên trái ( ⊣/,) vào tự ( ) và nối các cột ngoài cùng bên phải ( ,⊢/), tìm cực tiểu trong bộ ba ngang ( 3⌊/) và chuyển vị ( )

  • ⍵+ thêm giá trị của mỗi nút vào khoảng cách tối thiểu của nó cho hàng xóm

  • ⊢⌊ cố gắng để đánh bại khoảng cách tốt nhất hiện tại

⊃⌽, cuối cùng, trả về ô dưới cùng bên phải

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.