Mô phỏng truyền lửa


28

Giả sử chúng ta có một ma trận như thế này:

11111
12221
12321
12221
11111

Ma trận này đại diện cho một địa hình và mỗi ô đại diện cho một phần địa hình. Số lượng trong mỗi ô biểu thị thời gian phần địa hình cần được đốt cháy hoàn toàn (tính bằng phút, nếu cần một đơn vị đo lường), theo khả năng cháy của nó . Nếu đám cháy bắt đầu tại bất kỳ vị trí nào (ô), ô đó cần được đốt cháy hoàn toàn trước khi lửa truyền sang các ô liền kề (chỉ ngang và dọc, không chéo). Vì vậy, nếu đám cháy được bắt đầu ở vị trí trung tâm, đám cháy cần:

11111        11111        11111        11011        10001        00000
12221  3 m.  12221  2 m.  12021  1 m.  11011  1 m.  00000  1 m.  00000
12321 -----> 12021 -----> 10001 -----> 00000 -----> 00000 -----> 00000
12221        12221        12021        11011        00000        00000
11111        11111        11111        11011        10001        00000

Giải trình:

  • Lửa bắt đầu từ [2,2] (dựa trên 0), có thời gian cháy là 3.
  • Sau 3 phút, [1,2], [2,1], [2,3], [3,2] bắt đầu cháy.
  • Sau 2 phút, các tế bào đó kết thúc quá trình cháy và lửa lan truyền đến tất cả các ô lân cận, nhưng [0,2], [2,0], [2,4], [0,4] chỉ cần thêm 1 phút để đốt, vì vậy
  • Sau 1 phút, các tế bào đó bị cháy và tế bào lan truyền đến các tế bào lân cận của chúng.
  • Sau 1 phút nữa, các tế bào còn lại từ bước 3 kết thúc quá trình cháy và lửa lan truyền đến các ô liền kề của chúng (đã bị cháy, vì vậy không có gì xảy ra).
  • Sau 1 phút cuối, lửa kết thúc đốt cháy toàn bộ địa hình.

Vì vậy, giải pháp cho trường hợp đó là 8 phút. Nếu lửa bắt đầu ở ô trên cùng bên trái [0,0]:

11111     01111     00111     00011     00001     00000
12221  1  12221  1  02221  1  01221  1  00121  1  00011   1
12321 --> 12321 --> 12321 --> 02321 --> 01321 --> 00321  -->
12221     12221     12221     12221     02221     01221
11111     11111     11111     11111     11111     01111

00000     00000     00000     00000     00000
00000  1  00000  1  00000  1  00000  1  00000
00221 --> 00110 --> 00000 --> 00000 --> 00000
00221     00121     00020     00010     00000
00111     00011     00001     00000     00000

Vì vậy, bây giờ tổng thời gian là 10 phút.

Các thách thức

Cho một ma trận NxM (N> 0, M> 0) các giá trị nguyên biểu thị thời gian mà mọi ô cần được tiêu thụ hoàn toàn, hãy viết chương trình / hàm ngắn nhất lấy ma trận đó và một cặp số nguyên với vị trí mà lửa bắt đầu và trả lại / in thời gian cần thiết để ngọn lửa tiêu thụ hoàn toàn toàn bộ địa hình.

  • Mỗi tế bào sẽ có thời gian ghi dương (khác không). Bạn không thể giả sử một giá trị tối đa cho các ô.
  • Ma trận không cần phải vuông cũng không đối xứng.
  • Ma trận có thể là 0-index hoặc 1-index, tùy thích.
  • Vị trí có thể được cung cấp dưới dạng một tham số duy nhất với một bộ số nguyên, hai tham số riêng biệt với bất kỳ định dạng hợp lý nào khác.
  • Kích thước của ma trận không thể được chỉ định làm tham số đầu vào.
  • Bạn không cần phải xuất ra mọi bước trung gian, chỉ cần lượng thời gian được yêu cầu. Nhưng tôi sẽ không phàn nàn nếu các bước được hình dung theo bất kỳ cách nào.

Một vi dụ khac:

Fire starts at [1,1] (a '>' represents a minute):

4253   4253   4253   4153   4043   3033   2023    0001   0000
2213 > 2113 > 2013 > 1003 > 0002 > 0001 > 0000 >> 0000 > 0000 
1211   1211   1211   1111   1001   0000   0000    0000   0000

Output: 9

Đây là , vì vậy có thể chương trình ngắn nhất cho mỗi ngôn ngữ sẽ giành chiến thắng!


1
@LeanderMoesinger nó phải làm việc với bất kỳ ma trận nào. Ý tôi là chương trình hoặc hàm của bạn không thể chấp nhận các kích thước của ma trận làm tham số đầu vào, nhưng tất nhiên bạn có thể tính các kích thước đó bên trong mã của mình.
Charlie

Đầu vào có thể được lấy dưới dạng một số theo thứ tự chính cột không? Đó là, các mục ma trận được đánh số, sau đó xuyên suốt
Luis Mendo

1
@LuisMendo có, tất nhiên. Nhưng lưu ý rằng thời gian ghi của mọi ô có thể lớn hơn 9, nếu điều đó quan trọng đối với phần "số đơn".
Charlie

Cảm ơn. Không, nó không thành vấn đề. Tôi có nghĩa là một số duy nhất nhưng có thể với một vài chữ số. Con số sẽ dao động từ 1đếnM*N
Luis Mendo

Câu trả lời:


12

Matlab, 235 257 190 182 178 byte

Đầu vào: Ma trận A, vectơ 1x2 pchứa tọa độ bắt đầu.

function t=F(A,p)
[n,m]=size(A);x=2:n*m;x(mod(x,n)==1)=0;B=diag(x,1)+diag(n+1:n*m,n);k=sub2ind([n m],p(1),p(2));t=max(distances(digraph(bsxfun(@times,((B+B')~=0),A(:))'),k))+A(k)

Giải trình:

Thay vì mô phỏng việc truyền lửa, chúng ta cũng có thể hiểu đây là vấn đề "tìm con đường ngắn nhất dài nhất". Ma trận được chuyển đổi thành một biểu đồ định hướng có trọng số. Trọng số của các đường dẫn đến một nút tương ứng với thời gian ghi nút đã nói. Ví dụ cho một ma trận

5   7   7   10
5   2   2   10
4   5   2   6

chúng ta có được biểu đồ kết nối:

đồ thị

Trong đó nút 1 là phần tử ma trận trên bên trái và nút 12 là phần tử bên phải phía dưới. Cho tọa độ bắt đầu p, đường dẫn ngắn nhất đến tất cả các nút khác được tính toán. Sau đó, độ dài của đường dẫn dài nhất của các đường dẫn ngắn nhất đó + thời gian để đốt nút ban đầu bằng với thời gian để ghi toàn bộ ma trận.

Phiên bản Ungolfed và nhận xét với các giá trị bắt đầu mẫu:

% some starting point
p = [3 2];
% some random 5x6 starting map, integers between 1:10
A = randi(10,5,6); 

function t=F(A,p)
% dimensions of A
[n,m] = size(A);
% create adjacency matrix
x=2:n*m;
x(mod(x,n)==1)=0;
B = diag(x,1)+diag(n+1:n*m,n);
B = B+B';
B = bsxfun(@times,(B~=0),A(:))';
% make graph object with it
G = digraph(B);
% starting node
k = sub2ind([n m], p(1), p(2));
% calculate the shortest distance to all nodes from starting point
d = distances(G,k);
% the largest smallest distance will burn down last. Add burntime of initial point
t = max(d)+A(k);

1
Chào mừng đến với PPCG!
Stephen

Cách tiếp cận rất tốt đẹp và giải thích rất tốt!
Charlie

Này, vì đây là sân golf đầu tiên của tôi, tôi phải hỏi liệu có ổn không khi tôi bỏ qua ;sau mỗi dòng. Trong Matlab, điều này ngăn chặn kết quả của mỗi lệnh được hiển thị trong bàn điều khiển. Hiện tại mã RẤT trò chuyện và spam bảng điều khiển. Nhưng vì đó không phải là một trạng thái thất bại nghiêm ngặt nên tôi đã giữ nó như vậy. Nhưng nó không quan trọng lắm, chỉ là 4 byte
Leander Moesinger

1
@LeanderMoesinger thư rác có đi vào cùng khu vực đầu ra với đầu ra chương trình của bạn không? Nếu thư rác, ví dụ, đi vào STDERR hoặc tương đương và đầu ra đi vào STDOUT hoặc tương đương, bạn sẽ loại bỏ chúng tốt. Nếu cả hai đầu ra ở cùng một vị trí, tôi sẽ không biết.
Stephen

@ Đó là một khu vực đầu ra khác nhau, nhưng tôi có thể tránh nó hoàn toàn bằng cách đặt mọi thứ một dòng. Thx cho làm rõ!
Leander Moesinger

9

JavaScript (ES6), 156 152 146 144 143 byte

Đã lưu 1 byte nhờ Kevin Cruijssen

Một cách thực hiện khá ngây thơ. Đưa đầu vào theo cú pháp currying (a)(s), trong đó a là mảng 2D và s là mảng gồm hai số nguyên [ x, y ] đại diện cho tọa độ 0 của vị trí bắt đầu.

a=>s=>(g=t=>(a=a.map((r,y)=>r.map((c,x)=>(z=(h,v)=>(a[y+~~v]||[])[x+h]<1)(-1)|z(1)|z(0,-1)|z(0,1)|x+','+y==s&&c?u=c-1:c),u=-1),~u?g(t+1):t))(0)

Định dạng và nhận xét

a => s => (                                // given a and s
  g = t => (                               // g = recursive function with t = time counter
    a = a.map((r, y) =>                    // for each row r of the input array:
      r.map((c, x) =>                      //   for each cell c in this row:
        (                                  //     z = function that takes
          z = (h, v) =>                    //         2 signed offsets h and v and checks
            (a[y + ~~v] || [])[x + h] < 1  //         whether the corresponding cell is 0
        )(-1) | z(1) |                     //     test left/right neighbors
        z(0, -1) | z(0, 1) |               //     test top/bottom neighbors
        x + ',' + y == s                   //     test whether c is the starting cell
        && c ?                             //     if at least one test passes and c != 0:
          u = c - 1                        //       decrement the current cell / update u
        :                                  //     else:
          c                                //       let the current cell unchanged
      ),                                   //   end of r.map()
      u = -1                               //   start with u = -1
    ),                                     // end of a.map() --> assign result to a
    ~u ?                                   // if at least one cell was updated:
      g(t + 1)                             //   increment t and do a recursive call
    :                                      // else:
      t                                    //   stop recursion and return t
  )                                        // end of g() definition
)(0)                                       // initial call to g() with t = 0

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


==0có thể bị đánh gôn <1nếu tôi không nhầm.
Kevin Cruijssen

1
@KevinCruijssen Điều này thực sự an toàn như undefined<1là giả. Cảm ơn!
Arnauld

8

Octave, 67 byte

function n=F(s,a)n=0;do++n;until~(s-=a|=imdilate(~s,~(z=-1:1)|~z')

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

Để hình dung kết quả trung gian, bạn có thể thử điều này!

Một hàm lấy ma trận đầu vào của địa hình avà tọa độ ban đầu là ma trận 0 & 1 có cùng kích thước với địa hình.

endfunctionTuy nhiên, trên thực tế không cần thiết phải chạy ví dụ trong tio.

Giải trình:

Liên tục áp dụng sự giãn nở hình ảnh hình thái trên địa hình và trừ đi các khu vực bị đốt cháy từ đó.

Câu trả lời bất đắc dĩ:

function n = Fire(terrain,burned)
    n = 0;
    mask = [...
            0  1  0
            1  1  1
            0  1  0];
    while true
        n = n + 1;
        propagation = imdilate(~terrain, mask);
        burned = burned | propagation;
        terrain = terrain - burned;
        if all(terrain(:) == 0)
            break;
        end
    end
end

Đây là một câu trả lời hay, nhưng có lẽ thuật toán đang đếm trạng thái ban đầu là một bước và trả về 11 thay vì 10 trong ví dụ của bạn. Nếu tôi thay đổi ô ban đầu thành [3 3] thì kết quả là 9 thay vì 8.
Charlie

@CarlosAlejo OH, xấu của tôi. Trả lời cập nhật thay đổi n=1thành n=0.
rahnema1

7

MATL , 26 25 byte

Tôi thực sự muốn xem thêm một số câu trả lời bằng cách sử dụng các ngôn ngữ golf nhất ở đây

`yy)qw(8My~1Y6Z+fhy0>z}@&

Định dạng đầu vào là:

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

  • Đầu vào thứ hai là một số duy nhất giải quyết một mục nhập của ma trận theo thứ tự chính dựa trên cột 1 (được cho phép bởi thử thách). Ví dụ: tọa độ chính của cột của mỗi mục trong ma trận 3 × 4 được đưa ra bởi

    1  4  7 10
    2  5  8 11
    3  6  9 12
    

    Vì vậy, ví dụ tọa độ dựa trên 1 (2,2) tương ứng với 5.

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

Mã duy trì một danh sách các mục đang được ghi. Ở mỗi lần lặp, tất cả các mục trong danh sách đó đều được giảm. Khi một mục nhập bằng không, các mục lân cận của nó được thêm vào danh sách. Để lưu byte, các mục nhập bằng 0 không bị xóa khỏi danh sách; thay vào đó, họ tiếp tục "đốt cháy" với các giá trị âm. Vòng lặp được thoát khi không có mục nào có giá trị dương.

Xem chương trình đang chạy từng bước với mã sửa đổi một chút.

Mã nhận xét:

`      % Do...while
  yy   %   Duplicate top two arrays (matrix and array of positions to be decremented)
       %   In the first iteration this implicitly takes the two inputs
  )    %   Reference indexing. This gives the values that need to be decremented
  q    %   Decrement
  w    %   Swap. This brings the array of positions that have been decremented to top
  (    %   Assignment indexing. This writes the decremented values back into their
       %   positions
  8M   %   Push array of positions again
  y    %   Duplicate decremented matrix
  ~    %   Negate. This replaces zeros by 1, and nonzeros by 0
  1Y6  %   Push predefined literal [0 1 0; 1 0 1; 0 1 0] (4-neighbourhood)
  Z+   %   2D convolution, maintaining size
  f    %   Find: gives column-major indices of neighbours of totally burnt entries
  h    %   Concatenate. This updates the array of positions to be decremented
  y    %   Duplicate decremented matrix
  0>   %   This gives 1 for positive entries, and 0 for the rest
  z    %   Number of nonzeros. This is the loop condition (*)
}      % Finally (execute before exiting loop)
  @    %   Push iteration number. This is the output
  &    %   Specify that the final implicit display function will display only the top
       %   of the stack
       % Implicit end. If the top of the stack (*) is not 0 (i.e. there are entries
       % that have not been totally burnt) the loop proceeds with the next iteration.
       % Else the "finally" branch is executed and the loop is exited
       % Implicit display (only top of the stack)

2
Bây giờ đó là những gì tôi gọi là một mã ngắn! :-)
Charlie


4

Python 3 , 277 266 byte

def f(m,s):
 p={s};w=len(m);t=0
 while sum(sum(m,[])):
  t+=1;i=0
  for x,y in p:
   try:m[x][y]=max(0,m[x][y]-1)
   except:0
  for v in sum(m,[]):
   if v<1:
    for l in[(1,0),(-1,0),(0,1),(0,-1)]:a,b=max(0,i%w+l[0]),max(0,i//w+l[1]);p.add((a,b))
   i+=1
 print(t)

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

Xác định hàm flấy ma trận 2D và một tuple điểm. Điều đầu tiên mà hàm thực hiện là xác định một bộ các bộ chứa giá trị bộ dữ liệu ban đầu được truyền vào : p={s}. Sau đó, hàm sẽ đi qua từng bộ điểm pvà trừ một điểm khỏi ma trận mtại điểm đó, trừ khi giá trị này bằng không. Sau đó, nó lặp mlại tìm tất cả các điểm có giá trị 0 và thêm bốn lân cận của điểm đó vào tập hợp p. Đây là lý do tại sao tôi chọn sử dụng một tập hợp, bởi vì các tập hợp trong Python không cho phép các giá trị trùng lặp (điều này sẽ làm mất đi phép trừ rất nhiều). Thật không may, do gói chỉ mục danh sách (ví dụ list[-1] == list[len(list)-1]:) các chỉ số cần phải được ràng buộc để chúng không bị âm và thêm tọa độ sai vào p.

Không có gì đặc biệt, vẫn quen với việc chơi golf. Chắc chắn có chỗ để cải thiện ở đây, tôi sẽ tiếp tục bẻ khóa nó.


Bạn có thể viết một ví dụ thực hiện tại Dùng thử trực tuyến để tất cả chúng ta có thể kiểm tra mã của bạn không?
Charlie

@CarlosAlejo Tất nhiên, đã thêm nó vào bài viết.
MooseOnTheRocks

4

APL (Dyalog) , 93 66 57 byte

{⍵{^/,0≥⍺:0⋄1+x∇⍵∨{∨/,⍵∧⍲/¨2|⍳3 3}⌺3 30=x←⍺-⍵}(⊂⍺)≡¨⍳⍴⍵}

Hãy thử trực tuyến! hoặc trực quan hóa nó trực tuyến!


Hàm này lấy ma trận địa hình làm đối số bên phải và tọa độ (dựa trên 1) của lần bắn đầu tiên làm đối số bên trái. Trả về số phút cần thiết để ghi tất cả mọi thứ.


Cập nhật

Cuối cùng tìm thấy một cách để chơi golf xuống chức năng lây lan.
* Thở dài * sẽ dễ dàng hơn nhiều nếu thế giới hình xuyến .


TIO vừa nâng cấp lên Dyalog 16.0 , có nghĩa là bây giờ chúng ta có toán tử stprint mới sáng bóng


Câu trả lời rất hay! Đầu ra trung gian giúp hình dung sự tiến bộ!
Charlie

2

Python 2 , 268 byte

def f(m,y,x):t,m[y][x]=m[y][x],0;g(m,t)
def g(m,t):
	n,h,w=map(lambda r:r[:],m),len(m),len(m[0])
	for l in range(h*w):r,c=l/h,l%h;n[r][c]-=m[r][c]and not all(m[r][max(c-1,0):min(c+2,w+1)]+[m[max(r-1,0)][c],m[min(r+1,h-1)][c]])
	if sum(sum(m,[])):g(n,t+1)
	else:print t

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

Lặp đi lặp lại theo các bước theo thời gian trong đó số lượng của mỗi ô được giảm nếu nó nằm liền kề với một thuật toán 0. Rất đơn giản mà tôi tin rằng, vẫn có thể được đánh gôn để đạt hiệu quả boolean ...

* lưu ý: 'Hãy thử trực tuyến!' của tôi mã bao gồm ghi nhật ký gỡ lỗi trong phần chân trang. Tôi thích xem tiến trình thuật toán.


2

Haskell , 138 133 byte

u#g|all((<=0).snd)g=0|2>1=1+(u:[[(x+1,y),(x-1,y),(x,y-1),(x,y+1)]|((x,y),0)<-n]>>=id)#n where n=d<$>g;d p|elem(fst p)u=pred<$>p|2>1=p

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

Giả sử đầu vào là một danh sách ((x, y), ô). Ung dung:

type Pos = (Int, Int)

ungolfed :: [Pos] -> [(Pos, Int)] -> Int
ungolfed burning grid
  | all ((<=0).snd) grid = 0 
  | otherwise = 1 + ungolfed (burning ++ newburning) newgrid
 where
  newgrid = map burn grid
  burn (pos,cell) | pos `elem` burning = (pos, cell - 1)
                  | otherwise = (pos, cell)
  newburning = do
    ((x,y),cell) <- newgrid
    guard (cell <= 0)
    [(x+1,y),(x-1,y),(x,y-1),(x,y+1)]
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.