행렬을 통한 최적의 경로


19

양의 정수로 구성된 행렬이 주어지면 왼쪽 상단 요소에서 오른쪽 하단으로 이동할 때 합계가 가장 낮은 경로를 출력하십시오. 세로, 가로 및 대각선으로 이동할 수 있습니다. 위 / 아래, 오른쪽 / 왼쪽 및 대각선으로 모든면으로 이동할 수 있습니다.

예:

 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*

가장 낮은 합계를 제공하는 경로는 별표로 표시되며 결과는 1 + 4 + 1 + 1 + 1 + 5 + 1 + 9 = 23 입니다.

테스트 사례 :

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)

이것은 이므로 각 언어에서 가장 짧은 코드가 승리합니다.


대각선 이동은 허용하지 않지만 매우 유사 합니다.
Mego

7
@WheatWizard 동의하지 않습니다. 이 도전이 대각선 이동을 허용하고 모든 위치에 도달 할 수 있다는 대부분의 피상적 인 차이와는 별도로, 다른 도전은 단지 경로 비용이 아닌 경로 자체의 복귀를 요구합니다. 둘 다 반환하는 기본 제공 기능을 사용하지 않으면 코드를 서로 바꿀 수 없습니다.
비이커

@ beaker 나는 실제로 차이점을 보지 못합니다. 길이를 알 수있는 경로를 찾아야합니다. 여기의 차이점은 내 의견으로는 출력의 약간의 차이 이며이 도전은 이미 그 도전에서 다루지 않은 새롭거나 흥미로운 것을 제공하지 않습니다.
밀 마법사

1
@WheatWizard 내 솔루션이 경로를 찾지 못했습니다. 그것은 수있는 경로를 찾을 수 있지만 별도의 전임자 배열 및 로직없이 노드에게 자신의 이전을 방지하기 위해. 끝에 경로를 복구하는 것은 말할 것도 없습니다.
비커

@ beaker 내 의견으로는 수정이 다소 사소한 것입니다. 속임수의 문제에 관계없이 한 번의 도전에 대한 모든 유효한 단일 항목 을 최소한의 노력으로 포괄 할 수 있는지 여부 는 일반적인 경우와 관련이 없습니다. 나는 여기서 대부분의 노력이 포팅 될 수 있다고 생각할뿐만 아니라이 도전이 다른 것에서 새롭거나 흥미로운 것을 제공한다고 생각하지 않는다.
밀 마법사

답변:


8

자바 스크립트, 442 412 408 358 바이트

이것은 나의 첫 PPCG 제출입니다. 의견을 부탁드립니다.

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

이것은 다차원 배열을 입력으로 사용합니다.

설명

기본적으로 가장 낮은 알려진 비용을 조정하여 모든 셀을 반복해서 반복하여 각 이웃에 도달하십시오. 결국 그리드는 오른쪽 하단에 도달하는 총 비용이 가장 낮은 비용에 도달하는 상태에 도달합니다.

데모

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

편집 : 수십 개의 맛있는 바이트를 면도하는 데 도움을 주신 @ETHproductions 에게 특별한 감사를드립니다 .

@Stewie Griffin 에게 50 바이트 를 허비 한 팁에 감사드립니다 .


3
PPCG에 오신 것을 환영합니다! 끝까지 제거 할 수있는 여분의 공간이 있으며 (총 5 개 계산) 세미콜론이 필요하지 않습니다.} 몇 바이트를 절약해야 . 변수를 선언 할 필요도 없습니다. vars를 제거하면 총 24 바이트가 더 절약됩니다.
ETHproductions

2
PPCG에 오신 것을 환영합니다 =) 출발점으로 내 과제 중 하나를 선택하게되어 기쁩니다. 나의 유일한 의견 : 나는 설명을 좋아한다. 선택 사항이므로 원하지 않는 한 추가하지 않아도됩니다. :)
Stewie Griffin

아마도 m[v][t]변수로 저장하는 t=x+X;v=y+Y;k=m[v][t]것이 더 짧을 것입니다 ...?
Stewie Griffin


6

옥타브 + 화상 처리 패키지 (175) (162) 157 151 142 139 바이트

덕분에 14 바이트 절약 @Luis Mendo @notjagan 1 바이트 절약

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)

왜 이미지 프로세싱 패키지를 사용합니까? 모두가 그래프 문제를 해결하는 방법이 아닌가요?

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

폭발

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

설명

가중치가 주어지면 :

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

비용이 가중치와 동일한 시작점 (왼쪽 상단 요소)을 제외하고 모든 요소에 도달하는 비용이 무한대가되도록 비용 배열을 초기화하십시오.

  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

이는 반복 0입니다. 이후의 각 반복에 대해 셀에 도달하는 비용은 최소값으로 설정됩니다.

  • 해당 요소에 도달하기위한 현재 비용
  • 요소의 이웃에 도달하는 현재 비용 + 요소의 무게

첫 번째 반복 후 요소 (2,2)의 경로 비용 (1 기반 색인 사용)은 다음과 같습니다.

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

첫 번째 반복 후 전체 비용 배열은 다음과 같습니다.

  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

반복 후에 k는 각 요소가 대부분의 k단계 부터 시작하여 해당 요소에 도달하는 가장 낮은 비용이 됩니다. 예를 들어 (3,3)의 요소는 22 단계의 비용으로 2 단계 (반복)로 도달 할 수 있습니다.

  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

그러나 4 번째 반복에서는 비용이 20 인 4 단계의 경로가 발견됩니다.

 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

mxn 행렬을 통한 경로 는 행렬의 요소 수보다 길 수 없으므로 (매우 느슨한 상한값으로) m*n반복 후 모든 요소에는 시작부터 해당 요소에 도달하기위한 최단 경로 비용이 포함됩니다.


사이의 공간을 제거하여 -1 바이트 while~.
notjagan

@notjagan 난에서 전환 whilefor여전히 당신의 팁을 사용할 수 있었다. 감사!
비커

5

자바 스크립트, 197 바이트

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

확인 :

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

Mathematica 279 바이트

기본적인 아이디어는 정점 매트릭스 엔트리에 대응하는 두 꼭지점 사이 관한 에지에 의해 분리하여 그래프를 작성하는 ChessboardDistance0보다 큰 미만 또는 1 또한 동일, 이것은 알려진 우연히 킹 그래프 는에 대응하고 있기 때문에, 체스 판에서 왕의 유효한 움직임.

FindShortestPath그런 다음 최소 경로를 얻는 데 사용됩니다. 는에서 작동 EdgeWeight하지 않으므로 각 지정 모서리의 대상에 해당하는 행렬 항목으로 VertexWeight정의하는 추가 코드 EdgeWeight가 있습니다.

암호:

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

점을 유의 문자가 전치의 상징이다. 그대로 Mathematica에 붙여 넣습니다.

용법:

%@{{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

당신이 설정된 경우 g=Graph[...,GraphLayout->{"GridEmbedding","Dimension"->d},VertexLabels->Thread[s->m]p=FindShortestPath[...다음 그래픽 시각 (그래프 아래의 행렬에 상당 상단) 용액을 표시한다 :

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

여기에 이미지 설명을 입력하십시오


3

하스켈, 228 바이트

위치는 2 개의 요소로 생성 sequence하기 쉽고 패턴 일치하기 쉽기 때문에 두 요소의 목록입니다 .

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

시작하고 -1,-1각 단계 대상 필드의 비용을 계산하십시오.

대안적인 첫 두 줄 :에서 시작 0,0, 출발 필드 계산, 행렬 차원과 동일한 좌표에서 종료 (법적 대상 목록에 추가해야하는 목표에서 오른쪽 아래로)-길이는 동일하지만 느립니다.

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]

에 대한 접두사를 사용하면 map여기에 바이트가 저장되지 않지만 더 많은 용도로만 더 좋을 수 있고 때로는 다른 구조 조정을 사용하여 다른 괄호를 깎을 수 있기 때문에 비용이 들지 않는 즉시 대체합니다.

개선 : 중복 filter. 에 라이닝로 / 병합 filter(flip elem$(s$(\x->[0..x])#m)\\p)import Data.List대한 \\3 비용 바이트.

또한 너무 나쁘면 (fromEnumTo 0)2 바이트보다 깁니다 (\x->[0..x]).

sum$concat c모든 필드의 비용이 합산되어 minimum빈 목록을 피하기 위해 제공되는 경로 비용에 대해 간결하게 표현 가능한 상한입니다 (내 유형 검사기는 이미 모든 작업을 Integers에서 결정 했으므로 최대 값을 하드 코딩하지 않습니다. ). 이전 단계를 기반으로 한 단계를 제한하는 방법 (알고리즘 속도를 높이고 바이트 수)에 관계 없이이 폴백을 필요로하는 막 다른 골목을 피할 수는 없습니다.

  • 한 가지 필터 아이디어는 ((not.e n).zipWith(-)(head r))extracting n=s[[-1..1],[-1..1]]으로 시작되었으므로 ,[-1,-1]초기 경로에 추가 해야합니다. 그런 다음 알고리즘은 이전 단계에서 이미 갔을 수있는 곳으로가는 것을 피하여 엣지 필드에서 해당 엣지에 직교 적으로 스테핑을합니다.

  • 또 하나는 ((>=0).sum.z(*)d)extracting으로 재귀 및 초기 경우 와 같이 재귀 함수에 z=zipWith새로운 인수 d를 도입합니다 . 이 알고리즘은 음의 스칼라 곱 ( 이전 단계 임) 으로 연속적인 단계를 피 하므로 45도 회전이 급격하지 않습니다. 이것은 여전히 ​​선택의 폭을 좁히고 이전의 사소한 막 다른 골목을 피하지만 이미 방문한 들판으로 둘러싸여있는 경로가 있습니다 (그러나 아마도 '탈출'은 급격한 전환 일 것입니다).(z(-)p q)[1,1]d


3

파이썬 2, 356320 바이트

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

여기 사용해보십시오!

notjagan 덕분에 -36 바이트 !

목록을 입력으로 받아 행렬을 왼쪽 상단에서 오른쪽 하단으로 탐색 할 때 최저 비용을 출력합니다.

설명

행렬의 왼쪽 위에서 오른쪽 아래로 가능한 모든 경로를 찾아 각 경로에 대한 x, y 좌표 목록을 만듭니다. 경로는 역 추적 할 수 없으며로 끝나야합니다 (len(s)-1,len(s[0])-1).

각 좌표 경로의 정수를 합하고 최소 비용을 반환합니다.

print쉽게 출력 최단 경로에 대한 좌표의리스트를 변경할 수있다.


기타 변경 사항이있는 -36 바이트
notjagan

@notjagan 큰 변화, 특히 or조건 에 대한 사용 . 감사합니다!
Solvation

1

APL (Dyalog Classic) , 33 바이트

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

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

{ } 인수 기능

+\+⍀⍵ 경로 거리에 비관적 상한을 설정하기 위해 행과 열별로 부분 합을 취합니다.

( )⍣≡ 수렴 될 때까지 반복하십시오.

  • (⍉3⌊/⊣/,⊢,⊢/)⍣2이웃까지의 거리의 최소, 즉 두 번 ( ( )⍣2) : 가장 왼쪽 열 ( ⊣/,) 앞에 자기 ( )를 추가하고 가장 오른쪽 열 ( ,⊢/)을 추가 하고 가로 삼중 ( 3⌊/)으로 최소값을 찾고 조옮김 ( )

  • ⍵+ 이웃까지의 최소 거리에 각 노드의 값을 추가

  • ⊢⌊ 현재 최고의 거리를 이길려고

⊃⌽, 마지막으로 오른쪽 아래 셀을 반환

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