Prediksi Longsor

22

Tanah longsor

Dalam tantangan ini, tugas Anda adalah memperkirakan tingkat kerusakan yang disebabkan oleh tanah longsor besar-besaran. Kami menggunakan model dua dimensi berikut yang disederhanakan untuknya, diparameterisasi dengan tinggi awal h >= 0 dan koefisien kritis c > 0 . Anda mulai dengan tebing tinggi h, dan diasumsikan bahwa medannya benar-benar datar tak terbatas ke kiri dan ke kanan. Sebab h = 6, situasinya terlihat seperti ini:

##########
##########
##########
##########
##########
##########
-----------------------

Ini -adalah batuan dasar yang tidak tergoyahkan, dan #merupakan tanah yang tidak stabil. Jika perbedaan ketinggian antara dua kolom tetangga lebih dari c, tanah longsor terjadi: cunit teratas tanah dari kolom kiri jatuh ke ckolom berikutnya di sebelah kanan, satu ke masing-masing. Kolom non-kosong paling kanan pada gambar tidak stabil untuk c = 2, sehingga tanah longsor dipicu:

#########
#########
##########
##########
##########
############
-----------------------

Kolom masih tidak stabil, yang menyebabkan tanah longsor kedua:

#########
#########
#########
#########
############
############
-----------------------

Sekarang, kolom di sebelah kirinya menjadi tidak stabil, sehingga tanah longsor baru dipicu di sana:

########
########
#########
###########
############
############
-----------------------

Setelah ini, tebing kembali stabil. Yang menyenangkan dari model ini adalah urutan pemrosesan tanah longsor tidak menjadi masalah: hasil akhirnya sama.

Tugas

Program Anda diberi parameter bilangan bulat hdan csebagai input (urutannya tidak penting, tetapi Anda harus menentukannya pada jawaban Anda), dan itu akan menampilkan jumlah kolom yang dipengaruhi oleh tanah longsor. Ini berarti jumlah kolom di tebing stabil yang dihasilkan yang tingginya antara 0dan h. Dalam contoh di atas, output yang benar adalah 4.

Anda dapat menulis program atau fungsi lengkap. Hitungan byte terendah menang, dan celah standar tidak diizinkan.

Uji Kasus

Ini diberikan dalam format h c -> output.

0  2  -> 0
2  3  -> 0
6  2  -> 4
6  6  -> 0
10 1  -> 10
15 1  -> 14
15 2  -> 11
15 3  -> 6
40 5  -> 16
80 5  -> 28
80 10 -> 17
Zgarb
sumber

Jawaban:

5

CJam, 62 57 byte

Sejauh yang saya bisa lihat, ini adalah pendekatan yang sama sekali berbeda untuk mengimplementasikan solusi dari jawaban aditsu.

q~:C;:HaH)*H){(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h-H-,

Masukan berupa h c

Contoh:

80 5

Keluaran:

28

Bagaimana itu bekerja

Logikanya cukup lurus ke depan di sini dengan beberapa trik yang digunakan untuk mengurangi ukuran kode.

  • Dapatkan h + 1( + 1untuk h = 0kasus) array panjang dengan masing-masing elemen hmewakili tebing
  • Mulai iterasi dari indeks paling kanan array ini
    • Jika dua elemen dari indeks saat ini berbeda lebih dari c
      • Hapus cdari elemen indeks saat ini
      • Tambahkan 1ke celemen array selanjutnya dari indeks saat ini
      • Jadikan indeks saat ini sama dengan panjang array baru ini
      • Ini memastikan bahwa kami menstabilkan batu di sebelah kanan indeks saat ini terlebih dahulu
    • selain itu, kurangi indeks saat ini
  • Ketika kami menekan indeks paling kiri, kami memastikan bahwa semua indeks yang berdekatan memiliki kurang dari atau sama dengan cperbedaan
  • Hapus salah satu 0atau hnilai dari array dan dapatkan panjangnya.

Perluasan kode

q~:C;:HaH)*H){(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h-H-,
q~:C;:HaH)*H)
q~:C;:H                  "Read the input, evaluate it, store height in H and coeff. in C";
       aH)*              "Wrap the height number in an array and repeat it H + 1 times";
           H)            "Put H+1 on stack, representing the current index of iteration";
{(:I\_@>2<:-C>{I0a*C~)+C1a*+]z1fb_,}I?}h
(:I\_@>2<:-C>
(:I                      "Decrement the current index and store it in I";
   \_                    "Swap to put array on top and make 1 copy";
     @>2<                "Get the two elements starting from Ith index";
         :-              "Get the difference. The best part of this approach is that";
                         "For the right most index, where there is only element, it";
                         "returns the element itself, which is the expected difference";
           C>            "Check if difference is greater than C";
{I0a*C~)+C1a*+]z1fb_,}   "This block will be executed when the difference is more than C";
 I0a*                    "Get an array of I length and all elements 0";
     C~)+                "Get -C value and append it to the above array";
         C1a*+           "Get C length array of 1s and concat with the above array";
              ]          "Wrap the two arrays, the cliff and the above one in an array";
               z1fb      "Transpose to get number pairs and add those pairs. For example";
                         "If we are at the right most index with H = 80 and C = 5,";
                         "The right section of the cliff looks like:";
                         "[ ... 80 80 80 80 80] and the array created in above step";
                         "looks like [ ... 0 0 0 0 -5 1 1 1 1 1]. After z, we have:";
                         "[ ... [80 0] [80 0] [80 0] [80 0] [80 -5] [1] [1] [1] [1] [1]]";
                         "After 1fb we get [ ... 80 80 80 80 75 1 1 1 1 1]";
                   _,    "Take a copy of the above resultant array and take its length";
I?                       "If difference was not greater than C, put I on stack";
                         "Now we either have the decremented index or new array length";
                         "on stack."
{ ... }h                 "This is a do while loop which makes sure that we iterate to";
                         "the left of the array. This loops runs till the top stack";
                         "element is 0 while not popping the top element";
        -H-,             "After the loop, we have the final cliff array and 0 on stack";
                         "Remove any 0 elements from the array, then remove any H";
                         "elements from the array and then take length to get the";
                         "number of columns which were modified";

Cobalah online di sini

Pengoptimal
sumber
Digagalkan lagi: p Dilakukan dengan baik :)
aditsu
@aditsu lagi?
Pengoptimal
Ini bukan pertama kalinya seseorang mengalahkan saya di CJam. Dan bukan pertama kali Anda melakukannya juga, meskipun tidak yakin apakah Anda pernah melakukannya dalam kompetisi langsung sebelumnya.
aditsu
Heh :) Semuanya tentang algoritme :)
Pengoptimal
4

CJam - 70

q~:C;:H0]H*$W%{[__W<\1>]z{~-}%{C>}#):I{I(_2$=C-tC,{I+_2$=)t}/}0?}h-H-,

Cobalah di http://cjam.aditsu.net/

Penjelasan:

q~                    read and evaluate the input
:C;                   store the 2nd number in C and remove
:H                    store the first number in H
0]H*                  make an array [H 0] and repeat it H times
$W%                   sort and reverse, obtaining [(H H's) (H 0's)] (initial cliff)
{                     loop...
    [__W<\1>]         make an array with the cliff without the first column
                      and the cliff without the last column
    z{~-}%            subtract the 2 arrays to get the height differences
    {C>}#             find the index of the first height diff. greater than C
    ):I               increment and store in I
    {                 if the value is non-zero (i.e. landslide occurring)
        I(_2$=C-t     subtract C from the corresponding column height
        C,            make an array [0 1 ... C-1]
        {             for each of those numbers
            I+        add I, obtaining a column index where some soil falls
            _2$=)t    increment the column height
        }/            end loop
    }0?               else break outer loop; end if
}h                    ...while the condition is true
-H-                   remove all 0 and H from the final stable cliff
,                     count the remaining columns

The hOperator memeriksa nilai terakhir di stack tanpa menghapusnya. Jika terjadi tanah longsor, nilainya adalah array tebing, yang dievaluasi benar karena tidak kosong. Jika tidak, nilai terakhir adalah 0 (salah).
Jadi dalam kasus tanah longsor, loop berlanjut dengan array pada stack, jika tidak maka diakhiri dengan 0 didorong setelah array. 0 itu kemudian dihapus dari array oleh -operator berikutnya .

aditsu
sumber
4

Python, 200 190 174

h,c=input();q=[h]*h+[0]*h
try:
 while 1:
    d=[b-a for a,b in zip(q[1:],q)];g=max(d);a=d.index(g)
    for i in range(c):q[a+1+i]+=1/(g>c);q[a]-=1
except:print sum(h>i>0for i in q)

Versi yang diperluas:

h, c = input()
# Initialize the heights
q = [h]*h + [0]*h
try:
    while 1:
        # Difference between the heights
        d = [b-a for a,b in zip(q[1:],q)]
        # It may error here, when h == 0, but thats okay
        g = max(d)
        a = d.index(g)
        for i in range(c):
            # This is the termination condition, when g <= c
            q[a+1+i] += 1 / (g>c)
            # Save the newline; also move this line to after termination
            q[a] -= 1
except:
    # Count all heights that have changed
    print sum(h > i > 0 for i in q)

Sunting: Setelah beberapa pengoptimalan, saya menghilangkan terminasi loop canggung melalui break (menghemat 1 byte). Juga mengubah slide dari irisan menjadi berbasis loop.

Philipp
sumber
Bagus! Anda dapat menjatuhkan kurung kotak di dalam sumselama 2 byte. Selain itu, biasanya lebih baik untuk mendefinisikan program lengkap dengan Python, mengambil input h,c=input()dan mencetak hasilnya pada akhirnya.
Zgarb
Saya tidak melihat solusi ini dan memposting yang sedikit lebih buruk D: Oh well, kompetisi itu bagus. Mungkin saya akan melihat apakah saya dapat mencukur beberapa byte dari milik saya. By the way, membalik perbandingan Anda di Anda sumdapat menghemat satu: sum(h>i>0for i in q).
undergroundmonorail
@undergroundmonorail Saya berusaha keras, tetapi saya khawatir pendekatan Anda hanya lebih unggul :(. c=0menghemat satu byte (saya tidak dapat mengomentari jawaban Anda).
Philipp
4

Python 2 - 194 158 byte

h,c=input()
b=l=[h]*h+[0]*h
while b:
 b=0
 for i in range(len(l)-1):
  if l[i]-l[i+1]>c:
    for j in range(c):l[i-~j]+=1
    l[i]-=c;b=1
print sum(h>e>0for e in l)

(Perhatikan bahwa juru bahasa markdown SE mengonversi tab literal menjadi 4 spasi. Baris 7 dan 8 dari program ini hanya memiliki satu tab tunggal [yaitu satu byte] dari lekukan masing-masing.)

Mengambil input pada stdin, hpertama. Sebagai contoh:

$ ./landslide.py <<< '6, 2'
4

Program ini telah melalui banyak perbaikan. Saya telah mengedit jawaban ini untuk menjelaskan beberapa pengeditan yang lebih utama, tetapi agak lama. Anda dapat memeriksa riwayat edit jika Anda penasaran.

Penjelasan

Pertama, hdan cdibaca dari stdin. Dalam Python 2, input()sama dengan eval(raw_input()), itulah sebabnya saya meminta koma yang memisahkan angka. input()memberikan pengembalian sejumlah int, tidak perlu konversi.

Selanjutnya, daftar bilangan bulat dibuat. Itu 2*hpanjang. Paruh pertama adalah hdan babak kedua adalah 0. Saya tidak punya alasan untuk menunjukkan bahwa ini cukup untuk mensimulasikan infinite hs ke kiri dan 0s ke kanan. Saya hanya semacam tersandung ke dalamnya dan berfungsi untuk semua kasus uji, jadi jika seseorang dapat menemukan input tidak bekerja untuk saya dengan senang hati akan mengubahnya. Pokoknya, daftar ini dipanggil l, tetapi salinan lain dari itu dipanggil b.

bNilai sebenarnya tidak penting, yang penting adalah kebenaran. Daftar yang tidak kosong adalah benar dan satu-satunya cara bkosong di sini adalah jika h0, dalam hal ini jawaban yang benar masih dicetak. Dalam kasus lain, bharus jujur ​​untuk memastikan kita memasuki while b:loop. Namun, hal pertama yang terjadi di loop adalah pengaturan bke 0, nilai falsey. Selama setiap pengulangan loop bharus secara khusus diatur kembali ke yang benar atau loop akan berakhir.

Sisa dari loop adalah simulasi yang sebenarnya. Sangat naif, pada dasarnya hanya menjadi terjemahan kode dari deskripsi masalah. Jika ada elemen llebih dari yang clebih besar dari yang mengikutinya, itu dikurangi dengan cdan celemen berikutnya memiliki 1 ditambahkan ke mereka. (Sihir bitwise yang digunakan di sini hanyalah cara penulisan yang lebih pendek i+1+j, by the way.) Saat membuat transformasi ini, bdiatur ke 1. Pertama kali tidak ada transformasi yang dibuat, bakan tetap 0 dan loop berakhir.

Ekspresi sejati apa pun dievaluasi True, dan ketika Anda mencoba menghitungnya, Trueberarti bernilai 1. Hal yang sama juga berlaku pada False0. Baris terakhir program menggunakan setiap elemen lseperti edalam ekspresi h>e>0dan menjumlahkan hasilnya. Ini mendapatkan jumlah kolom lebih besar dari 0 tetapi lebih rendah dari ketinggian tebing asli, yang merupakan nilai yang diminta pertanyaan. Ini dicetak dan program keluar.

monmon bawah tanah
sumber
2
Tidak c-=csetara dengan c=0?
Zgarb
...Wow. terima kasih telah memperhatikan punggungku, aku seharusnya menangkapnya, haha
undergroundmonorail
1
i+1+jdapat ditulis sebagaii-~j
Sp3000
@ Sp3000 Saya benar-benar lupa tentang sihir bitwise! Terima kasih: D
undergroundmonorail
3

Haskell, 163 156 151 Bytes

h#c=sum[1|e<-(until=<<((==)=<<))s$r h++r 0,e`mod`h/=0]where r=replicate$h+1;s w@(x:y:z)|x==0=w|x>c+y=x-c:map(+1)(take c(y:z))++drop c(y:z)|1<2=x:s(y:z)

Penggunaan:, h#cmisalnya 6#2keluaran mana 4.

Cara kerjanya: fungsi helper smelakukan sekali longsor. Berlaku berulang ssampai output tidak berubah lagi. Hitung elemen yang terpengaruh.

Menemukan fungsi "terapkan sampai keluaran tidak berubah" (yaitu until=<<((==)=<<)) di Stackoverflow .

nimi
sumber
Anda dapat menyimpan beberapa byte dengan mendefinisikan fsebagai infix ( h#c=...) dan memindahkan whereklausa ke baris yang sama. Juga, masih ada beberapa tanda kurung untuk digunakan $, meskipun saya tidak yakin berapa banyak ...
Zgarb
@ Zgarb: terima kasih atas petunjuknya. Mengganti ()dengan $jejak dan kesalahan bagi saya.
nimi
3

Mathematica, 108 104 100 97 95

f=Max@#-Min@#&[0Range@#2//.{x___,k:##..&[a_,{#}],a_,y___}:>Sort@{x,##&@@({k}-1),a+#,y}/.{}->0]&

Pemakaian:

f[c, h]

Contoh:

f[5, 80]

28

alephalpha
sumber
2

C # 303 295

Berhasil!

Tapi itu ....

int q(int n,int c){var s=Enumerable.Repeat(n,n).ToList();s.Add(0);var d=new HashSet<int>();var g=true;while(g){g=false;for(int i=s.Count-1;i>0;i--){int z=i;int y=i-1;if((s[y]-s[z])>c){s[y]-=c;d.Add(y);g=true;for(int j=1;j<=c;j++){s[y+j]++;d.Add(y+j);if(s[s.Count-1]>0)s.Add(0);}break;}}}return d.Count;}

Saya harus menemukan bahasa baru;)

Saya akan memeriksa hal CJam ini ...

Ditingkatkan:

int q(int n,int c){var s=Enumerable.Repeat(n,n).ToList();s.Add(0);var d=new HashSet<int>();var g=1>0;while(g){g=1<0;for(int i=s.Count-1;i>0;i--){int z=i,y=i-1;if((s[y]-s[z])>c){s[y]-=c;d.Add(y);g=1>0;for(int j=1;j<=c;j++){s[y+j]++;d.Add(y+j);if(s[s.Count-1]>0)s.Add(0);}break;}}}return d.Count;}
mike m
sumber
1
Anda masih bisa sedikit mengoptimalkan ini. int z=i;int y=i-1;bisa jadi int z=i,y=i-1;. The forloop tidak melakukan rumit hal-hal dengan indeks mereka, sehingga misalnya for(int i=s.Count-1;i>0;i--)bisa for(int i=s.Count;--i>0;).1<0adalah cara penulisan yang lebih pendek false. Saya menduga itu if(s[s.Count-1]>0)s.Add(0);bisa kehilangan kondisi tanpa mempengaruhi kebenaran, hanya kecepatan.
Peter Taylor
@ Peter Taylor. Terima kasih!
mike m