미로의 컷 포인트


13

미로는 편리한 형식으로 0 (벽)과 1 (걸을 수있는 공간)의 행렬로 제공됩니다. 각 셀은 4 개 이하의 직교 이웃에 연결된 것으로 간주됩니다. 연결 컴포넌트는 모든 이적 서로 접속 걷기 셀의 집합이다. 당신의 임무는 컷 포인트 를 식별하는 것입니다 -벽으로 변할 경우 연결된 구성 요소의 수를 바꾸는 걸을 수있는 셀. 해당 위치에서만 1로 부울 행렬을 출력합니다. 목표는 가장 적은 바이트의 코드로 수행하는 것입니다.

입력 행렬은 3 행 이상 3 열 이상으로 구성됩니다. 하나 이상의 세포가 벽이되고 하나는 걸을 수 있습니다. TIO에서 (또는 언어가 TIO에서 지원되지 않는 경우 사용자의 컴퓨터 에서) 1 분 이내에 아래의 예제 나 기능 또는 프로그램을 처리 할 수 ​​있어야합니다 .

in:
11101001
11011101
00000001
11101111
11110101
00011111
10110001
11111111
out:
01000000
00001001
00000001
00000101
00110000
00010000
00000000
11100000

in:
1111111111111111
1000000000000001
1111111111111101
0000000000000101
1111111111110101
1000000000010101
1011111111010101
1010000001010101
1010111101010101
1010101111010101
1010100000010101
1010111111110101
1010000000000101
1011111111111101
1000000000000001
1111111111111111
out:
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000

in:
1011010001111010
1111111011101101
1110010101001011
1111001110010010
1111010000101001
0111101001000101
0011100111110010
1001110011111110
0101000011100011
1110110101001110
0010100111000110
1000110111011010
0100101000100101
0001010101100011
1001010000111101
1000111011000010
out:
0000000000111010
1011110001001000
0000000000000011
0000000100010000
0000010000101000
0000001000000100
0000000011000000
1001100000011110
0000000001000010
0110100001000110
0000100101000010
1000100000000000
0100001000000100
0000000100100001
0000010000111000
0000010000000010

따라서 모든 하위 그래프에서 모든 다리를 찾으십시오
HyperNeutrino

1
과제는 더 작은 매트릭스에 대한 단계별 예제에서 도움이 될 것이라고 생각합니다.
Mr. Xcoder

1
@HyperNeutrino 교량 은 다른 점이 있습니다. 이것은 연결된 구성 요소의 수를 증가 시키는 모서리 (정점 아님)입니다.
ngn

1
@HyperNeutrino 또한, 서브 그래프연결된 구성 요소
ngn

1
@Notatree 당신이 맞아요. 제가 실수를. 지금 고치기에는 너무 늦었지만 재미를 망치지 않기를 바랍니다.
ngn

답변:


3

Stax , 40 바이트

Çóê↓â.Φ}╞│*w<(♦◙¼ñ£º█¢,D`ì♥W4·☺╛gÇÜ♠╗4D┬

테스트 케이스 실행 및 디버그

이 프로그램은 행을 포함하는 공백으로 구분 된 문자열로 입력을받습니다. 출력 형식이 동일합니다. 압축을 푼 아스키 표현입니다.

{2%{_xi48&GxG=-}_?m}{'1'2|e{"12|21".22RjMJguHgu%

섬을 계산하는 기본 동작은 다음과 같습니다.

  1. 첫 번째를 '1'로 바꿉니다 '2'.
  2. 대체 정규식 '12|21'으로 '22'.
  3. 공백으로 나눕니다.
  4. 전치 행렬.
  5. 문자열이 반복 될 때까지 2부터 반복하십시오.
  6. '1'문자열에 더 이상 a가 없을 때까지 1부터 반복하십시오 . 반복 횟수는 아일랜드 수입니다.

.

{               start map block over input string, composed of [ 01]
  2%            mod by 2. space and 0 yield 0. 1 yields 1. (a)
  {             start conditional block for the 1s.
    _           original char from string (b)
    xi48&       make copy of input with current character replaced with 0
    G           jump to unbalanced }, then return; counts islands (c)
    xG          counts islands in original input (d)
    =           are (c) and (d) equal? 0 or 1 (e)
    -           b - e; this is 1 iff this character is a bridge
  }             end conditional block
  _?            execute block if (a) is 1, otherwise use original char from string
m               close block and perform map over input
}               goto target - count islands and return
{               start generator block
  '1'2|e        replace the first 1 with a 2
  {             start generator block
    "12|21".22R replace "12" and "21" with "22"
    jMJ         split into rows, transpose, and rejoin with spaces
  gu            generate values until any duplicate is encountered
  H             keep the last value
gu              generate values until any duplicate is encountered
%               count number of iterations it took

보너스 44 바이트 프로그램 -이 버전은 그리드 형식을 사용하여 입력 및 출력합니다.


컴퓨터에서 1 분 안에 두 번째 예를 처리합니까?
ngn

@ngn : Chrome의이 중간 범위 노트북에서 41 대의 세 가지 예를 모두 수행합니다. 또한 방금 메인 링크를 수정했습니다. 실수로 오래된 비 작동 버전으로 설정했습니다.
재귀

3

MATL , 26 바이트

n:"GG0@(,w4&1ZIuz]=~]vGZye

입력은 ;행 분리 자로 사용되는 숫자 형 행렬 입니다.

온라인으로 사용해보십시오! 또는 모든 테스트 사례를 확인하십시오 .

설명

n           % Implicit input: matrix. Push number of elements, N
:           % Range: gives [1 2 ... N]
"           % For each k in [1 2 ... N]
  GG        %   Push input matrix twice
  0@(       %   Write 0 at position k (in column-major order: down, then across).
            %   The stack now contains the original matrix and a modified matrix
            %   with 0 at position k
  ,         %   Do twice
    w       %     Swap
    4       %     Push 4. This specifies 4-element neighbourhood
    &1ZI    %     Label each connected component, using the specified
            %     neighbourhood. This replaces each 1 in the matrix by a
            %     positive integer according to the connected component it
            %     belongs to
    u       %     Unique: gives a vector of deduplicate elements
    z       %     Number of nonzeros. This is the number of connected components
  ]         %   End
  =~        %   Are they different? Gives true of false
]           % End
v           % Concatenate stack into a column vector
GZye        % Reshape (in column-major order) according to size of input matrix.
            % Implicit display

2

펄 (5) , -p0 105 (101) 96 93 90 89 바이트

입력 b대신에 사용 합니다 1.

STDIN의 행렬이 줄 바꿈으로 끝나는 지 확인하십시오.

#!/usr/bin/perl -p0
s%b%$_="$`z$'";s:|.:/
/>s#(\pL)(.{@{-}}|)(?!\1)(\pL)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg

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

3 단계의 대체물을 사용합니다!

이 87 바이트 버전은 입력 및 출력 형식으로 해석하기 쉽지만 출력에 3 개의 다른 문자를 사용하므로 경쟁하지 않습니다.

#!/usr/bin/perl -0p
s%b%$_="$`z$'";s:|.:/
/>s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se&&y/{c/z />0:seg&/\B/%eg

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

s영숫자가 아닌 다른 문자를 개행 문자 대신 행 종결 자로 사용하여 두 버전에서 다른 바이트 (정규식 수정 자)를 쉽게 저장할 수 있지만 입력을 다시 읽을 수 없게 만듭니다.

작동 원리

대체를 고려하십시오

s#(\w)(.{columns}|)(?!1)(\w)#c$2c#s

가로와 세로가 서로 다른 두 글자를 찾아서로 바꿉니다 c. 경로가 완전히 문자로 구성된 미로에서는 b글자가 동일하기 때문에 아무 일도 일어나지 않지만, 글자 중 하나가 다른 글자로 대체되는 즉시 (예 :) z그 글자와 이웃이 바뀌고 c반복되는 적용은 c시드로 연결된 구성 요소의 플러드 채우기 z.

그러나이 경우에는 완전한 홍수 채우기를 원하지 않습니다. 나는 인접한 팔 중 하나만 채우고 싶기 z때문에 첫 번째 단계 후에 나는 z사라지 기를 원합니다 . 그것은 이미 c$2c교체 와 함께 작동 하지만 나중에 같은 지점에서 시작하여 다른 팔을 따라 플러드 필을 다시 시작하고 싶습니다 . 더 이상 c원래 s가 무엇인지 알 수 z없습니다. 대신에 나는

s#(\w)(.{columns}|)(?!\1)(\w)#$&|a.$2.a#se

b | ais c, b | cis cand z | ais {입니다. 그래서으로 구성 경로와 미로 b와 씨앗 z첫 번째 단계는 b대체 얻을 것이다 cz대체 얻을 것이다 {편지 쓰기하지 않고 일치하지 않는 \w등하지 않습니다 더 채우기 원인. 는 c그러나가는 더 홍수 채우기를 유지하고 씨의 한 이웃 암이 채워집니다. 예를 들어

  b                      c
  b                      c
bbzbb       becomes    bb{bb
  b                      b
  b                      b

그런 다음 모든 c를 문자가 아닌 다른 문자 (예 -:) {로 바꾸고 z다시 채워서 홍수 채우기를 다시 시작할 수 있습니다.

  -                      -
  -                      -
bbzbb       becomes    cc{bb
  b                      b
  b                      b

시드의 모든 이웃이 변환 될 때까지이 과정을 반복하십시오. 나는 다음 한 번 더 교체하는 경우 {z홍수 채우기 :

  -                      -
  -                      -
--z--       stays      --z--
  -                      -
  -                      -

z끝에 뒤에 남아로의 변환을 수행 할 이웃이 없기 때문입니다. 그것은 다음 코드 조각에서 일어나는 일을 분명히합니다.

/\n/ >                                    

첫 번째 줄 바꿈을 찾으십시오. 시작 오프셋은 이제@-

s#(\w)(.{@{-}}|)(?!\1)(\w)#$&|a.$2.a#se

위에서 설명한 정규 표현식 @{-}은 열 수로 설명했습니다 (일반적으로 @-perl 파서를 혼동하고 올바르게 대체하지 않기 때문에)

&&

/\n/우리는 여전히 홍수로 채워질 수 있는 한 항상 성공하고 대체는 사실입니다. 따라서 &&한 팔의 플러드 필이 완료되면 이후 부품 이 실행됩니다. 왼쪽이 아닌 경우 빈 문자열로 평가

y/{c/z / > 0

플러드 필을 다시 시작하고 이전 플러드 필이 어떤 작업을 수행 한 경우 1을 반환하십시오. 그렇지 않으면 빈 문자열을 반환하십시오. 이 전체 코드는 안에 싸여 있습니다

s:|.: code :seg

이것은 시작하는 문자열에서 실행되는 경우 그래서 $_z종자의 위치에 코드 내부의 조각은 대부분 아무 것도 반환하지 않습니다 여러 번 실행됩니다하지만 1때마다 이웃 암 홍수 채워진 가져옵니다. 연결된 구성 요소가 연결되어있는만큼 효과적으로 $_파괴되고 교체됩니다 . 루프는 구성 요소 크기 + 총 횟수의 합까지 실행되어야하지만 "개행 * 2 + 1을 포함하는 문자 수"번이므로 괜찮습니다.1z

1의 (빈 문자열, 분리 된 정점)이 없거나 팔이 2 개 이상 (2 1초 이상) 인 경우 미로는 연결이 끊어집니다 . 이것은 정규식을 사용하여 확인할 수 있습니다 /\B/( 이전 펄 버전 0대신 제공 합니다 1. 어느 것이 잘못 되었는가는 논란의 여지가 있습니다). 불행히도 일치하지 않으면 대신 빈 문자열이 제공됩니다 0. 그러나이 s:|.: code :seg항상 수행하여 이렇게 홀수를 반환하도록 설계되었습니다 &/\B/이 줄 것이다 01.

남은 것은 전체 입력 배열과 걸어서 갈 수있는 각 위치에서 z연결된 암을 걸고 연결하는 것입니다. 그것은 쉽게 수행됩니다 :

s%b%$_="$`z$'"; code %eg

유일한 문제는 걸을 수없는 위치에서 이전 값이 유지된다는 것입니다. 0여기에 s 가 필요하기 때문에 원래 입력 배열은 0걷기 불가능한 위치에 있어야 하고 원래 대체와 0일치 해야하며 \w플러드 필을 트리거합니다. 그래서 \pL대신 대신 문자를 사용 합니다.


2

자바 (8), (503) 489 459 455 바이트

int R,C,v[][];m->{int c[][]=new int[R=m.length][C=m[0].length],r[][]=new int[R][C],i=R*C,t,u;for(;i-->0;)c[t=i/C][u=i%C]=m[t][u];for(;++i<R*C;r[t][u]=i(c)!=i(m)?1:0,c[t][u]=m[t][u])c[t=i/C][u=i%C]=0;return r;}int i(int[][]m){int r=0,i=0,t,u;for(v=new int[R][C];i<R*C;)if(m[t=i/C][u=i++%C]>v[t][u]){d(m,t,u);r++;}return r;}void d(int[][]m,int r,int c){v[r][c]=1;for(int k=-3,t,u;k<4;k+=2)if((t=r+k/2)>=0&t<R&(u=c+k%2-k/2)>=0&u<C&&m[t][u]>v[t][u])d(m,t,u);}

@ceilingcat 덕분에 -18 바이트 .

설명:

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

int R,C,                    // Amount of rows/columns on class-level
    v[][];                  // Visited-matrix on class-level

m->{                        // Method with int-matrix as both parameter and return-type
  int c[][]=new int[R=m.length][C=m[0].length],
                            //  Create a copy-matrix, and set `R` and `C`
      r[][]=new int[R][C],  //  Create the result-matrix
      i=R*C,                //  Index-integer
      t,u;                  //  Temp integers
  for(;i-->0;)              //  Loop `i` over each cell:
    c[t=i/C][u=i%C]=m[t][u];//   And copy the values of the input to the copy-matrix
  for(;++i<R*C              //  Loop over the cells again:
      ;                     //    After every iteration:
       r[t][u]=i(c)!=i(m)?  //     If the amount of islands in `c` and `m` are different
        1                   //      Set the current cell in the result-matrix to 1
       :                    //     Else:
        0,                  //      Set it to 0
       c[t][u]=m[t][u])     //     And set the copy-value back again
    c[t=i/C][u=i%C]=0;      //   Change the current value in the copy-matrix to 0
  return r;}                //  Return the result-matrix

// Separated method to determine the amount of islands in a matrix
int i(int[][]m){
  int r=0,                  //  Result-count, starting at 0
      i=0,                  //  Index integer
      t,u;                  //  Temp integers
  for(v=new int[R][C];      //  Reset the visited array
      i<R*C;)               //  Loop over the cells
    if(m[t=i/C][t=i++%C]    //   If the current cell is a 1,
       >v[t][u]){           //   and we haven't visited it yet:
      d(m,i,j);             //    Check every direction around this cell
      r++;}                 //    And raise the result-counter by 1
   return r;}               //  Return the result-counter

// Separated method to check each direction around a cell
void d(int[][]m,int r,int c){
  v[r][c]=1;                //  Flag this cell as visited
  for(int k=-3,u,t;k<4;k+=2)//  Loop over the four directions:
    if((t=r+k/2)>=0&t<R&(u=c+k%2-k/2)>=0&u<C
                            //   If the cell in the direction is within bounds,
       &&m[t][u]            //   and it's a path we can walk,
         >v[t][u])          //   and we haven't visited it yet:
      d(m,i,j);}            //    Do a recursive call for this cell

1

파이썬 2 , 290 바이트

lambda m:[[b([[C and(I,J)!=(i,j)for J,C in e(R)]for I,R in e(m)])!=b(eval(`m`))for j,c in e(r)]for i,r in e(m)]
def F(m,i,j):
	if len(m)>i>=0<=j<len(m[i])>0<m[i][j]:m[i][j]=0;F(m,i,j+1);F(m,i,j-1);F(m,i+1,j);F(m,i-1,j)
b=lambda m:sum(F(m,i,j)or c for i,r in e(m)for j,c in e(r))
e=enumerate

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

Rod 덕분에
-11 바이트 Lynn 덕분에 -11 바이트


1
F(m,i,j)각 요소 에 사용 하는 것이 더 짧아 11 바이트를 절약
Rod

for q in((i,j+1),(i,j-1),(i+1,j),(i-1,j)):-> for q in(i,j+1),(i,j-1),(i+1,j),(i-1,j):-rm 외부 파 렌
ngn

F암시 적으로 반환 하기 때문에 대신 None사용할 수 있습니다 . F(m,i,j)or c[F(m,i,j)]and c
Lynn

또한 일 and m[i][j]수 있고 >0<m[i][j][q[:]for q in m]수 있습니다 eval(`m`).
Lynn

@ 린은 eval ( 'm')을 의미합니까? 동일한 목록 인스턴스를 반환하지 않습니까?
ngn


1

자바 스크립트 122 바이트

여러 줄 문자열로 입력 / 출력합니다.

m=>m.replace(/./g,(v,p,m,n=[...m],f=p=>n[p]==1&&(n[p]=0,v=f(p-1)+f(p+1)+f(p-w)+f(p+w)-1?1:0,1))=>(f(p),v),w=~m.search`\n`)

걸을 수있는 각 셀에 대해 블록을 배치하고 4 개의 인접 셀을 채우십시오. 현재 셀이 컷 포인트가 아닌 경우 열린 이웃에서 시작하면 모든 셀이 채워집니다. 그렇지 않으면 모든 인접 셀에 도달하기 위해 하나 이상의 채우기 작업이 필요합니다.

덜 골프

m=>{
  w = m.search('\n') + 1; // offset to the next row
  result = [...m].map( // for each cell
     ( v, // current value
       p  // current position
     ) => {
     n = [...m]; // work on a copy of the input
     // recursive fill function from position p
     // returns 1 if managed to fill at least 1 cell
     fill = (p) => {
        if (n[p] == 1)
        {
           n[p] = 0;
           // flag will be > 1 if the fill from the current point found disjointed areas
           // flag will be 0 if no area could be filled (isolated cell)
           var flag = fill(p+1) + fill(p-1) + fill(p+w) + fill(p-w);
           // v is modified repeatedly, during recursion
           // but I need the value at top level, when fill returns to original caller
           v = flag != 1 ? 1 : 0;
           return 1; // at least 1 cell filled
        }
        else
           return 0; // no fill
     }
     fill(p)
     return v // orginal value or modified by fill function
  }) 
}

테스트

var F=
m=>m.replace(/./g,(v,p,m,n=[...m],f=p=>n[p]==1&&(n[p]=0,v=f(p-1)+f(p+1)+f(p-w)+f(p+w)-1?1:0,1))=>(f(p),v),w=~m.search`\n`)

var test=`in:
11101001
11011101
00000001
11101111
11110101
00011111
10110001
11111111
out:
01000000
00001001
00000001
00000101
00110000
00010000
00000000
11100000

in:
1111111111111111
1000000000000001
1111111111111101
0000000000000101
1111111111110101
1000000000010101
1011111111010101
1010000001010101
1010111101010101
1010101111010101
1010100000010101
1010111111110101
1010000000000101
1011111111111101
1000000000000001
1111111111111111
out:
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000
0000000000000000

in:
1011010001111010
1111111011101101
1110010101001011
1111001110010010
1111010000101001
0111101001000101
0011100111110010
1001110011111110
0101000011100011
1110110101001110
0010100111000110
1000110111011010
0100101000100101
0001010101100011
1001010000111101
1000111011000010
out:
0000000000111010
1011110001001000
0000000000000011
0000000100010000
0000010000101000
0000001000000100
0000000011000000
1001100000011110
0000000001000010
0110100001000110
0000100101000010
1000100000000000
0100001000000100
0000000100100001
0000010000111000
0000010000000010
`.match(/\d[10\n]+\d/g);
for(i = 0; test[2*i]; ++i)
{
   input = test[2*i]
   check = test[2*i+1]
   result = F(input)
   ok = check == result
   console.log('Test '+ i + ' ' + (ok?'OK':'FAIL'),
   '\n'+input, '\n'+result)
}

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