Điểm cắt trong mê cung


13

Một mê cung được đưa ra dưới dạng ma trận 0s (tường) và 1s (không gian có thể đi bộ) ở bất kỳ định dạng thuận tiện nào. Mỗi ô được coi là kết nối với 4 (hoặc ít hơn) hàng xóm trực giao của nó. Một thành phần được kết nối là một tập hợp các ô có thể đi bộ được kết nối liên tục với nhau. Nhiệm vụ của bạn là xác định các điểm cắt - các ô có thể đi được, nếu được biến thành các bức tường, sẽ thay đổi số lượng các thành phần được kết nối. Xuất ra một ma trận boolean chỉ có 1 giây tại các vị trí đó. Mục tiêu là làm điều đó trong vài byte mã nhất.

Ma trận đầu vào sẽ bao gồm ít nhất 3 hàng và 3 cột. Ít nhất một trong các tế bào của nó sẽ là một bức tường và ít nhất một tế bào sẽ có thể đi được. Chức năng hoặc chương trình của bạn phải có thể xử lý bất kỳ ví dụ nào dưới đây trong một phút trên TIO (hoặc trên máy tính của riêng bạn, nếu ngôn ngữ không được TIO hỗ trợ).

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

vì vậy, tìm tất cả các cây cầu trong tất cả các sơ đồ con
HyperNeutrino

1
Tôi nghĩ rằng thách thức sẽ được hưởng lợi từ một ví dụ từng bước cho một ma trận nhỏ hơn.
Ông Xcoder

1
@HyperNeutrino một cây cầu có gì đó khác biệt - đó là một cạnh (không phải là một đỉnh) mà việc loại bỏ làm tăng số lượng các thành phần được kết nối
ngn

1
@HyperNeutrino cũng vậy, một sơ đồ con không hoàn toàn giống như một thành phần được kết nối
ngn

1
@Notatree Bạn nói đúng. Tôi đã phạm một sai lầm. Bây giờ đã quá muộn để sửa nó nhưng tôi hy vọng nó sẽ không làm hỏng cuộc vui.
ngn

Câu trả lời:


3

Stax , 40 byte

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

Chạy và gỡ lỗi các trường hợp thử nghiệm

Chương trình này lấy đầu vào là một chuỗi phân tách không gian chứa các hàng. Đầu ra có cùng định dạng. Đây là đại diện ascii đã giải nén.

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

Các hoạt động cơ bản để đếm một hòn đảo hoạt động như thế này.

  1. Thay cái đầu tiên '1'bằng a '2'.
  2. Regex thay thế '12|21'bằng '22'.
  3. Chia trên không gian.
  4. Ma trận chuyển vị.
  5. Lặp lại từ 2. cho đến khi một chuỗi được lặp lại.
  6. Lặp lại từ 1. cho đến khi không còn a '1'trong chuỗi. Số lần lặp lại là số lượng đảo.

.

{               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

Phần thưởng 44 byte chương trình - phiên bản này nhập và xuất bằng định dạng lưới.


nó có xử lý ví dụ thứ hai dưới một phút trên máy tính của bạn không?
ngn

@ngn: Nó thực hiện cả ba ví dụ trong 41 giây trên máy tính xách tay tầm trung này trong Chrome. Ngoài ra, tôi chỉ sửa liên kết chính. Tôi vô tình để nó được đặt thành một phiên bản không hoạt động cũ.
đệ quy

3

MATL , 26 byte

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

Đầu vào là một ma trận số, sử dụng ;như dấu phân cách hàng.

Hãy thử trực tuyến! Hoặc xác minh tất cả các trường hợp thử nghiệm .

Giải trình

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

Perl 5 , -p0 105 101 96 93 90 89 byte

Sử dụng bthay vì 1trong đầu vào.

Đảm bảo ma trận trên STDIN được kết thúc bằng một dòng mới

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

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

Sử dụng 3 cấp độ thay thế!

Phiên bản 87 byte này có cả định dạng đầu vào và đầu ra dễ hiểu hơn, nhưng không cạnh tranh vì nó sử dụng 3 ký tự khác nhau trong đầu ra:

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

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

Thật dễ dàng để lưu một byte khác (công cụ ssửa đổi biểu thức chính) trong cả hai phiên bản bằng cách sử dụng một số ký tự khác nhau (không phải chữ và số) làm dấu kết thúc hàng (thay vì dòng mới), nhưng điều đó làm cho đầu vào khá khó đọc trở lại.

Làm thế nào nó hoạt động

Hãy xem xét sự thay thế

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

Điều này sẽ tìm thấy hai chữ cái khác nhau và nằm cạnh nhau theo chiều ngang hoặc chiều dọc và thay thế chúng bằng c. Trong một mê cung có đường dẫn hoàn toàn là chữ cái bsẽ không có gì xảy ra vì các chữ cái giống nhau, nhưng ngay khi một trong các chữ cái được thay thế bằng một chữ cái khác (ví dụ z) chữ cái đó và hàng xóm sẽ được thay thế cvà ứng dụng lặp đi lặp lại là một lấp đầy các thành phần được kết nối với ctừ hạt giốngz .

Trong trường hợp này, tuy nhiên tôi không muốn lấp đầy hoàn toàn. Tôi muốn chỉ lấp đầy một trong những cánh tay lân cận z, vì vậy sau bước đầu tiên tôi muốn zđi. Điều đó đã hoạt động với sự c$2cthay thế, nhưng sau đó tôi muốn khởi động lại một vùng lũ dọc theo một nhánh khác bắt đầu từ cùng một điểm và tôi không biết cái nào cban đầu znữa. Vì vậy, thay vì tôi sử dụng

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

b | ac, b | ccz | a{. Vì vậy, trong một mê cung với những con đường được tạo thành bvà một hạt giống ztrong bước đầu tiên bsẽ được thay thế czsẽ được thay thế bởi {đó không phải là một chữ cái và không khớp \wvà do đó sẽ không gây ra thêm. Các ctuy nhiên sẽ giữ thêm lũ điền đi và một cánh tay người hàng xóm của hạt giống được lấp đầy. Ví dụ: bắt đầu từ

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

Sau đó tôi có thể thay thế tất cả c bởi một số phi chữ cái (ví dụ -) và thay thế {bằng zmột lần nữa để khởi động lại lũ điền:

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

và lặp lại quá trình này cho đến khi tất cả các hàng xóm của hạt giống đã được chuyển đổi. Nếu tôi sau đó một lần nữa thay thế {bởi zlũ điền:

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

Phần zcòn lại phía sau ở cuối vì không có hàng xóm để thực hiện chuyển đổi. Điều đó làm rõ những gì xảy ra trong đoạn mã sau:

/\n/ >                                    

Tìm dòng mới đầu tiên. Phần bù bắt đầu hiện tại@-

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

Regex đã thảo luận ở trên với @{-}số lượng cột (vì đơn giản là @-nhầm lẫn trình phân tích cú pháp perl và không thay thế đúng cách)

&&

Các /\n/luôn thành công và sự thay thế là đúng miễn là chúng ta vẫn có thể lũ điền. Vì vậy, phần sau &&được thực hiện nếu việc lấp đầy một cánh tay được thực hiện. Nếu không bên trái ước tính thành một chuỗi rỗng

y/{c/z / > 0

Khởi động lại vùng lũ và trả lại 1 nếu lần lũ trước đó làm bất cứ điều gì. Khác trả lại chuỗi trống. Toàn bộ đoạn mã này được bọc bên trong

s:|.: code :seg

Vì vậy, nếu điều này được thực thi trên chuỗi bắt đầu $_với zvị trí hạt giống, đoạn mã bên trong sẽ được thực thi nhiều lần, hầu như không trả về gì ngoài 1mỗi lần cánh tay hàng xóm bị ngập nước. Hiệu quả $_bị phá hủy và thay thế bởi nhiều 1s như có các thành phần được kết nối với z. Lưu ý rằng vòng lặp cần được thực hiện tối đa bằng kích thước thành phần + số lần sử dụng vũ khí nhưng điều đó không sao vì nó sẽ "số lượng ký tự bao gồm cả dòng mới * 2 + 1" lần.

Mê cung bị ngắt kết nối nếu không có 1(chuỗi trống, đỉnh bị cô lập) hoặc nếu có nhiều hơn 1 nhánh (hơn 2 1giây). Điều này có thể được kiểm tra bằng regex /\B/(cái này 0thay vì 1trên các phiên bản perl cũ hơn. Người ta cho rằng cái nào sai). Thật không may nếu nó không khớp, điều này sẽ cung cấp một chuỗi trống thay vì 0. Tuy nhiên, s:|.: code :segđược thiết kế để luôn trả về một số lẻ, vì vậy bằng cách thực hiện &với /\B/điều này sẽ cho 0hoặc 1.

Tất cả những gì còn lại là đi bộ toàn bộ mảng đầu vào và tại mỗi hạt giống vị trí có thể đi bộ với zvà đếm các cánh tay được kết nối. Điều đó dễ dàng thực hiện với:

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

Vấn đề duy nhất là ở các vị trí không thể đi bộ, giá trị cũ được giữ lại. Vì chúng ta cần 0có nghĩa là mảng đầu vào ban đầu phải có 0ở các vị trí không thể đi bộ và 0khớp với vị trí \wthay thế ban đầu và sẽ kích hoạt lấp đầy lũ. Đó là lý do tại sao tôi sử dụng \pLthay thế (chỉ khớp các chữ cái).


2

Java 8, 503 489 459 455 byte

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

-18 byte nhờ @ceilingcat .

Giải trình:

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

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

Python 2 , 290 byte

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

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

-11 byte nhờ Rod
-11 byte nhờ Lynn


1
Nó ngắn hơn để sử dụng F(m,i,j)cho mỗi phần tử, tiết kiệm 11 byte
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 parens bên ngoài
ngn

Kể từ khi Ftrả về ngầm None, bạn có thể sử dụng F(m,i,j)or cthay vì [F(m,i,j)]and c.
Lynn

Ngoài ra, and m[i][j]có thể >0<m[i][j], và [q[:]for q in m]có thể eval(`m`).
Lynn

@Lynn bạn có nghĩa là eval ('m')? sẽ không trả lại cùng một danh sách ví dụ?
ngn


1

Javascript 122 byte

Đầu vào / đầu ra dưới dạng một chuỗi nhiều dòng.

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

Đối với mỗi ô có thể đi bộ, đặt một khối và cố gắng điền vào 4 ô lân cận. Nếu ô hiện tại không phải là điểm cắt, thì bắt đầu từ bất kỳ hàng xóm mở nào sẽ điền vào tất cả chúng. Khác, tôi sẽ cần nhiều hơn một thao tác điền để tiếp cận tất cả các ô lân cận.

Ít chơi gôn

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

Kiểm tra

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

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.