Simulator perambatan api


28

Misalkan kita memiliki matriks seperti ini:

11111
12221
12321
12221
11111

Matriks ini mewakili medan, dan setiap sel mewakili sebagian medan. Jumlah di setiap sel mewakili waktu bagian medan perlu dibakar sepenuhnya (dalam hitungan menit, jika unit pengukuran diperlukan), sesuai dengan kemampuan terbakarnya . Jika api mulai pada posisi tertentu (sel), sel itu harus benar-benar terbakar sebelum api merambat ke sel-sel yang berdekatan (hanya horisontal dan vertikal, bukan diagonal). Jadi, jika api dimulai pada posisi tengah, api membutuhkan:

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

Penjelasan:

  • Api dimulai pada [2,2] (berbasis 0), yang memiliki waktu bakar 3.
  • Setelah 3 menit, [1,2], [2,1], [2,3], [3,2] mulai terbakar.
  • Setelah 2 menit, sel-sel itu berakhir terbakar dan merambat ke semua sel yang berdekatan, tetapi [0,2], [2,0], [2,4], [0,4] hanya perlu 1 menit lagi untuk terbakar, jadi
  • Setelah 1 menit, sel-sel itu dibakar dan sel merambat ke sel-sel yang berdekatan.
  • Setelah 1 menit lagi, sisa sel dari langkah 3 berakhir terbakar dan merambat ke sel-sel yang berdekatan (yang sudah terbakar, sehingga tidak terjadi apa-apa).
  • Setelah 1 menit terakhir, api berakhir membakar seluruh medan.

Jadi solusi untuk kasus itu adalah 8 menit. Jika api dimulai di sel paling kiri atas [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

Jadi sekarang total waktu adalah 10 menit.

Tantangan

Diberikan matriks NxM (N> 0, M> 0) dari nilai integer yang mewakili waktu setiap sel perlu dikonsumsi sepenuhnya, tulis program / fungsi terpendek yang mengambil matriks dan sepasang bilangan bulat dengan posisi api dimulai pada , dan mengembalikan / mencetak waktu yang dibutuhkan api untuk sepenuhnya menghabiskan seluruh medan.

  • Setiap sel akan memiliki waktu pembakaran positif (bukan nol). Anda tidak dapat mengasumsikan nilai maksimum untuk sel.
  • Matriks tidak harus persegi atau simetris.
  • Matriks dapat 0-diindeks atau 1-diindeks, seperti yang Anda inginkan.
  • Posisi dapat diberikan sebagai parameter tunggal dengan tupel bilangan bulat, dua parameter terpisah dari format beralasan lainnya.
  • Dimensi matriks tidak dapat ditentukan sebagai parameter input.
  • Anda tidak perlu menampilkan setiap langkah perantara, cukup jumlah waktu yang diminta. Tetapi saya tidak akan mengeluh jika langkah-langkah tersebut divisualisasikan dengan cara apa pun.

Contoh lain:

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

Ini adalah , jadi semoga program terpendek untuk setiap bahasa menang!


1
@LeanderMoesinger itu harus bekerja dengan matriks apa pun. Maksud saya adalah bahwa program atau fungsi Anda tidak dapat menerima dimensi dari matriks sebagai parameter input, tetapi tentu saja Anda dapat menghitung dimensi tersebut di dalam kode Anda.
Charlie

Bisakah input diambil sebagai nomor tunggal dalam urutan kolom-utama ? Artinya, entri matriks diberi nomor, kemudian di seberang
Luis Mendo

1
@LuisMendo ya, tentu saja. Tetapi perhatikan bahwa waktu pembakaran setiap sel bisa lebih besar dari 9, jika itu penting untuk bagian "bilangan tunggal".
Charlie

Terima kasih. Tidak, itu tidak masalah. Maksud saya satu nomor tetapi mungkin dengan beberapa digit. Jumlah tersebut akan berkisar dari 1keM*N
Luis Mendo

Jawaban:


12

Matlab, 235 257 190 182 178 byte

Input: Matriks A, vektor 1x2 yang pberisi koordinat awal.

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)

Penjelasan:

Alih-alih mensimulasikan penyebaran api, kita juga bisa memahami ini sebagai masalah "temukan jalur terpendek terpanjang". Matriks tersebut dikonversi menjadi grafik terarah tertimbang. Bobot jalur ke satu simpul sesuai dengan waktu untuk membakar simpul tersebut. Misalnya untuk sebuah matriks

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

kami mendapatkan grafik yang terhubung:

grafik

Di mana simpul 1 adalah elemen matriks kiri atas dan simpul 12 elemen kanan bawah. Diberikan koordinat awal p, jalur terpendek ke semua node lainnya dihitung. Kemudian panjang jalur terpanjang dari jalur terpendek tersebut + waktu untuk membakar simpul awal sama dengan waktu untuk membakar seluruh matriks.

Versi tidak dikoleksi dan dikomentari dengan nilai awal sampel:

% 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
Selamat datang di PPCG!
Stephen

Pendekatan yang sangat bagus dan dijelaskan dengan sangat baik!
Charlie

Hei, karena ini golf pertama saya, saya harus bertanya apakah tidak apa-apa saya menghilangkan ;setelah setiap baris. Di Matlab, ini mencegah agar hasil setiap perintah ditampilkan di konsol. Saat ini kodenya SANGAT cerewet dan spam konsol. Tapi karena itu bukan keadaan kegagalan yang ketat saya tetap seperti itu. Tapi itu tidak masalah, hanya 4 byte
Leander Moesinger

1
@LeanderMoesinger apakah spam masuk ke area output yang sama dengan output program Anda? Jika spam, misalnya, masuk ke STDERR atau setara dan hasilnya masuk ke STDOUT atau setara, Anda harus menghapusnya. Jika keduanya menghasilkan di tempat yang sama, saya tidak akan tahu.
Stephen

@ Ini adalah area output yang berbeda, tapi saya bisa menghindarinya dengan meletakkan semuanya dalam satu baris. Terima kasih untuk klarifikasi!
Leander Moesinger

9

JavaScript (ES6), 156 152 146 144 143 byte

Disimpan 1 byte berkat Kevin Cruijssen

Implementasi yang agak naif. Mengambil input dalam sintaks currying (a)(s), di mana a adalah 2D-array dan s adalah array dua bilangan bulat [ x, y ] yang mewakili koordinat berbasis 0 dari posisi awal.

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)

Diformat dan dikomentari

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

Uji kasus


==0bisa bermain golf <1jika saya tidak salah.
Kevin Cruijssen

1
@KevinCruijssen Ini benar-benar aman seperti yang undefined<1salah. Terima kasih!
Arnauld

8

Oktaf, 67 byte

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

Cobalah online!

Untuk memvisualisasikan hasil antara, Anda dapat Coba ini!

Suatu fungsi yang mengambil sebagai matriks masukan medan adan koordinat awal sebagai matriks 0 & 1 dengan ukuran yang sama dengan medan.

Sebenarnya tidak perlu endfunctionuntuk menjalankan contoh di tio itu harus ditambahkan.

Penjelasan:

Lakukan pelebaran gambar morfologis berulang kali pada medan dan kurangi area yang terbakar darinya.

Jawaban yang tidak digabungkan:

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

Ini adalah jawaban yang bagus, tetapi mungkin algoritme menghitung keadaan awal sebagai langkah, dan mengembalikan 11 sebagai ganti 10 pada contoh Anda. Jika saya mengubah sel awal menjadi [3 3] hasilnya adalah 9 bukannya 8.
Charlie

@CarlosAlejo OH, salahku Jawaban yang diperbarui diubah n=1menjadi n=0.
rahnema1

7

MATL , 26 25 byte

Saya benar-benar ingin melihat beberapa jawaban lagi menggunakan bahasa golf di sekitar sini

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

Format input adalah:

  • Input pertama adalah matriks yang digunakan ;sebagai pemisah baris.

  • Input kedua adalah nomor tunggal yang membahas entri matriks dalam urutan kolom-mayor 1 berbasis (diizinkan oleh tantangan). Misalnya, koordinat kolom-utama dari setiap entri dalam matriks 3 × 4 diberikan oleh

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

    Jadi misalnya koordinat berbasis 1 (2,2) sesuai dengan 5.

Cobalah online! Atau verifikasi semua kasus uji .

Penjelasan

Kode memelihara daftar entri yang terbakar. Pada setiap iterasi, semua entri dalam daftar itu dikurangi. Ketika sebuah entri mencapai nol, entri yang berdekatan ditambahkan ke daftar. Untuk menyimpan byte, entri yang mencapai nol tidak dihapus dari daftar; alih-alih, mereka terus "membakar" dengan nilai negatif. Loop keluar ketika tidak ada entri yang memiliki nilai positif.

Lihat program yang menjalankan langkah demi langkah dengan kode yang sedikit dimodifikasi.

Kode yang dikomentari:

`      % 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
Nah, itu yang saya sebut kode pendek! :-)
Charlie

4

Python 2 , 170 byte

s,m=input()
t={s}
r=0
while max(sum(m,[]))>0:
 r+=1
 for a,b in t|t:
	try:a<0<x;b<0<x;m[a][b]-=1;t|=m[a][b]==0and{(a+1,b),(a-1,b),(a,b+1),(a,b-1)}or t^t
	except:0
print r

Cobalah online!


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)

Cobalah online!

Menentukan fungsi fyang mengambil matriks 2D dan tupel poin. Hal pertama fungsi adalah menentukan satu set tupel mengandung nilai tuple awal disahkan pada: p={s}. Fungsi kemudian melewati setiap tuple titik pdan mengurangi satu dari matriks mpada titik itu, kecuali nilainya sudah nol. Kemudian loop mlagi menemukan semua poin dengan nilai nol dan menambahkan empat tetangga dari titik itu ke set p. Inilah sebabnya saya memilih untuk menggunakan set, karena set dengan Python tidak mengizinkan nilai duplikat (yang akan mengacaukan pengurangan banyak). Sayangnya, karena pembungkus indeks daftar (misalnya list[-1] == list[len(list)-1]:) indeks perlu dibatasi sehingga mereka tidak pergi negatif dan menambahkan koordinat yang salah p.

Tidak ada yang istimewa, masih membiasakan diri bermain golf. Pasti ruang untuk perbaikan di sini, saya akan terus melakukannya.


Bisakah Anda menulis contoh eksekusi di Coba online sehingga kita semua dapat menguji kode Anda?
Charlie

@CarlosAlejo Tentu saja, menambahkannya ke pos.
MooseOnTheRocks

4

APL (Dyalog) , 93 66 57 byte

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

Cobalah online! atau Visualisasikan secara online!


Fungsi ini mengambil matriks medan sebagai argumen kanan dan koordinat (berbasis 1) dari api pertama sebagai argumen kiri. Mengembalikan jumlah menit yang dibutuhkan untuk membakar semuanya.


Pembaruan

Akhirnya menemukan cara untuk menurunkan fungsi penyebaran.
* Menghela nafas * akan jauh lebih mudah jika dunia ini toroidal .


TIO baru saja ditingkatkan ke Dyalog 16.0 , yang berarti sekarang kami memiliki operator stensil baru yang mengkilap


Jawaban yang sangat bagus! Output menengah membantu memvisualisasikan kemajuan!
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

Cobalah online!

Ulangi secara berulang-ulang seiring waktu langkah-langkah di mana setiap nomor ubin dikurangi jika berbatasan kardinal dengan 0. Algoritma yang sangat mudah, saya percaya, masih bisa digunakan untuk efisiensi boolean ...

* catatan: my 'Coba online!' kode termasuk bonus debug logging di footer. Saya suka melihat perkembangan algoritma.


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

Cobalah online!

Asumsikan input adalah daftar ((x, y), sel). Tidak Terkumpul:

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)]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.