Laser Schrödinger


24

Muak dengan bereksperimen pada hewan peliharaan kecil , pemenang hadiah Nobel Erwin Schrödinger telah memutuskan untuk menemukan laser terdekat dan menembaknya pada berbagai hal. Karena ... sains!

Deskripsi

Anda akan diberikan dua titik yang dilewati laser dan ukuran sinar laser, dan Anda harus menentukan ke mana sinar laser itu harus pergi, bisa pergi, dan tidak bisa pergi.

Sinar laser bisa horisontal, vertikal, atau diagonal. Untuk sinar laser ukuran 1, mereka terlihat seperti ini masing-masing:

       #  #
       #   #
#####  #    #
       #     #
       #      #

Sinar laser diagonal juga bisa dibalik. Sinar laser ukuran 2 terlihat seperti ini:

       ###  ##
#####  ###  ###
#####  ###   ###
#####  ###    ###
       ###     ##

Secara umum, untuk mendapatkan sinar laser ukuran (n), cukup ambil sinar laser ukuran (n-1) dan tambahkan sinar laser ukuran (1) di kedua sisi. Sebagai contoh terakhir, berikut adalah semua kemungkinan sinar laser ukuran 3, ditampilkan pada "papan" yang sama:

###.....#####.....##
####....#####....###
#####...#####...####
.#####..#####..#####
..#####.#####.#####.
...###############..
....#############...
.....###########....
####################
####################
####################
####################
####################
.....###########....
....#############...
...###############..
..#####.#####.#####.
.#####..#####..#####
#####...#####...####
####....#####....###

"Papan" ini akan selalu memiliki dimensi 20x20 (dalam karakter).

Memasukkan

Program Anda akan diberikan lima bilangan bulat sebagai input. Mereka, dalam urutan, x 1 , y 1 , x 2 , y 2 , dan ukuran sinar laser. Mereka harus diambil tepat dalam urutan itu. Jika mau, Anda dapat mengambil pasangan yang dipesan (x, y) sebagai larik, tupel, daftar, atau tipe data bawaan lainnya yang menyimpan dua nilai.

Kedua poin yang diberikan sebagai input akan berada di dalam papan, dan keduanya dijamin berbeda (yaitu dua poin tidak akan pernah sama). Ukuran sinar laser terikat 1 ≤ size < 20. Akan selalu ada setidaknya satu sinar laser yang mungkin melewati kedua titik.

Keluaran

Program Anda harus menampilkan kisi 20x20 karakter berikut:

  • # jika setiap kemungkinan sinar laser yang melewati dua titik juga melewati titik ini.
  • . jika tidak ada sinar laser yang melewati dua titik dan titik ini.
  • ? jika beberapa, tetapi tidak semua, sinar laser yang mungkin melewati titik ini.
  • Xjika ini adalah salah satu dari dua titik input asli (ini menimpa #).

Uji kasus

7, 7, 11, 3, 1

..............#.....
.............#......
............#.......
...........X........
..........#.........
.........#..........
........#...........
.......X............
......#.............
.....#..............
....#...............
...#................
..#.................
.#..................
#...................
....................
....................
....................
....................
....................

18, 18, 1, 1, 2

#??.................
?X??................
??#??...............
.??#??..............
..??#??.............
...??#??............
....??#??...........
.....??#??..........
......??#??.........
.......??#??........
........??#??.......
.........??#??......
..........??#??.....
...........??#??....
............??#??...
.............??#??..
..............??#??.
...............??#??
................??X?
.................??#

10, 10, 11, 10, 3

?????..????????..???
??????.????????.????
????????????????????
????????????????????
.???????????????????
..??????????????????
????????????????????
????????????????????
????????????????????
????????????????????
??????????XX????????
????????????????????
????????????????????
????????????????????
????????????????????
..??????????????????
.???????????????????
????????????????????
????????????????????
??????.????????.????

3, 3, 8, 10, 4

??????????..........
??????????..........
??????????..........
???X??????..........
???##?????..........
???###????..........
????###????.........
.????###????........
..????###????.......
..?????##?????......
..??????X??????.....
..??????????????....
..???????????????...
..????????????????..
..?????????????????.
..??????????????????
..??????????????????
..????????.?????????
..????????..????????
..????????...???????

Kasing uji dibuat dengan skrip Ruby berikut, yang terletak di dalam Cuplikan Stack untuk menghemat ruang vertikal.

Aturan

  • Program Anda harus dapat menyelesaikan setiap kasus uji dalam waktu kurang dari 30 detik (pada mesin yang masuk akal). Ini lebih merupakan pemeriksaan kewarasan, karena program Ruby pengujian saya menyelesaikan semua kasus pengujian secara instan.

  • Ini adalah , sehingga solusi terpendek menang.


2
Terminologi yang digunakan di sini awalnya membuat saya tersandung. Saya percaya laser biasanya mengacu pada perangkat yang menghasilkan sinar laser . Apa yang kamu wakili di sini benar-benar balok, kan? Ini tidak seharusnya menjadi representasi dari laser yang sebenarnya, yang akan menjadi perangkat yang menghasilkan balok?
Reto Koradi

2
Kasus tes terakhir terlihat salah. Laser ukuran 4 harus lebar 9 piksel. Jalur vertikal setidaknya harus selebar itu, tetapi sebenarnya lebih sempit.
Level River St

1
@steveverrill Ukuran 4 adalah 7 piksel lebar. Lebar dalam piksel adalah 2 * size - 1. Ukuran 1 adalah 1 piksel, ukuran 2 adalah 3 piksel, ukuran 3 adalah 5 piksel (lihat contoh di atas), ukuran 4 adalah 7 piksel.
Reto Koradi

2
Saya tidak melihat bagaimana Schrodinger terkait dengan tantangan ini.
user12205

1
@JonasDralle Sekali lagi, batas waktu sebagian besar hanya pemeriksaan kewarasan, dan hampir setiap pengajuan diharapkan selesai dalam waktu yang jauh lebih sedikit dari itu.
Gagang Pintu

Jawaban:


5

C, 291 280 277 265 byte

x,y,A,C,B,D,a,c,b,d,w,s,t;T(i){return abs(i)<2*w-1;}U(j,k){s+=T(j-k)*T(j)*T(k);t*=T(j-k)*j*k<1;}main(){for(scanf("%i%i%i%i%i",&a,&b,&c,&d,&w);y<20;y+=!x)s=0,t=1,U(A=a-x,C=c-x),U(B=b-y,D=d-y),U(A-B,C-D),U(A+B,C+D),putchar((x=++x%21)?".?#x"[!!s+t+(!A*!B+!C*!D)]:10);}

Dapat dikompilasi / dijalankan menggunakan:

gcc laser.c -o laser && echo "10 10 11 10 3" | ./laser

Di bawah, kode yang sama dengan spasi dan komentar penjelasan:

// Integers...
x,y,A,C,B,D,a,c,b,d,w,s,t;

// Is true if i is in range (of something)
T(i){return abs(i)<2*w-1;}

// Tests if lasers (horizontal, vertical, diagonal, etc) can/must exist at this point
// T(j-k) == 0 iff the laser of this direction can exist
// s += 1 iff this laser direction can pass through this point
// t *= 1 iff this laser direction must pass through this point
U(j,k){
    s+=T(j-k)*T(j)*T(k);
    t*=T(j-k)*j*k<1;
}

main(){ 
    // Read input; p0=(a,b), p1=(c,d)
    for(scanf("%i%i%i%i%i",&a,&b,&c,&d,&w); y<20; y+=!x)

        // A, B, C and D represent delta-x and delta-y for each points
        // e.g.: if we're processing (2,3), and p0=(4,5), A=4-2, B=5-3
        // s != 0 iff (x,y) can have some laser through it
        // t == 1 iff all lasers pass through (x,y)
        // (!A*!B+!C*!D) == 1 iff (x,y) is either p0 or p1  
        s=0,t=1,U(A=a-x,C=c-x),U(B=b-y,D=d-y),U(A-B,C-D),U(A+B,C+D),
        putchar((x=++x%21)?".?#x"[!!s+t+(!A*!B+!C*!D)]:10);
}

1
U(int j,int k)-> U(j,k); '\n'-> 10.
user12205

1
k<=0->k<1
user12205

Poin bagus. Saya akan memilih jika saya bisa!
André Harder

4

C, 302 byte

b[400],x,y,s,t,w,d,e,g,k;f(u,v){d=u*x+v*y;e=u*s+v*t;if(e<d)k=e,e=d,d=k;for(k=0;k<400&d+w>e;++k)g=k%20*u+k/20*v,b[k]|=g>e-w&g<d+w|(g<d|g>e)*2;}main(){scanf("%d%d%d%d%d",&x,&y,&s,&t,&w);w=2*w-1;f(1,0);f(0,1);f(1,1);f(1,-1);b[y*20+x]=4;b[t*20+s]=4;for(k=0;k<400;)putchar(".#.?X"[b[k]]),++k%20?0:puts("");}

Input diambil dari stdin, membaca 5 angka dalam urutan yang ditentukan.

Sebelum langkah pengurangan ukuran akhir:

#include <stdio.h>
#include <stdlib.h>

int b[400], x, y, s, t, w, d, e, g, k;

void f(int u, int v) {
  d = u * x + v * y;
  e = u * s + v * t;
  if (e < d) k = e, e = d, d = k;
  if (d + w > e) {
    for (k = 0; k < 400; ++k) {
      g = u * (k % 20) + v * (k / 20);
      if (g > e - w && g < d + w) b[k] |= 1;
      if (g < d || g > e) b[k] |= 2;
    }
  }
}

int main() {
  scanf("%d%d%d%d%d", &x, &y, &s, &t, &w);
  w = 2 * w - 1;
  f(1, 0); f(0, 1); f(1, 1); f(1, -1);
  b[y * 20 + x] = 4;
  b[t * 20 + s] = 4;
  for (k = 0; k < 400; ) {
     putchar(".#.?X"[b[k]]);
     ++k % 20 ? 0 : puts("");
  }
}

Beberapa penjelasan langkah-langkah utama:

  • Array bmemegang status / hasil. Bit 0 akan ditetapkan untuk semua piksel yang dapat dijangkau oleh balok. Bit 1 akan ditetapkan untuk semua piksel yang tidak tercakup oleh semua balok.
  • Fungsi fdipanggil untuk semua 4 arah (vertikal, horizontal, kedua diagonal). Argumennya menentukan vektor normal dari arah.
  • Dalam fungsi f:
    • Jarak dari kedua titik input relatif terhadap arah dihitung ( ddan e) sebagai produk titik dari titik dengan vektor normal dilewatkan.
    • Jarak ditukar jika perlu sehingga dselalu kurang dari atau sama dengan e.
    • Jika perbedaan antara ddan elebih besar dari lebar balok, tidak ada balok yang mungkin untuk arah ini.
    • Jika tidak, putar semua piksel. Tetapkan bit 0 jika piksel dapat dijangkau oleh sinar apa pun, dan bit 1 jika tidak tercakup oleh semua balok.
  • Tandai dua titik input dengan nilai 4. Karena kami menggunakan bit 0 dan 1 untuk melacak status, yang menghasilkan nilai 0 hingga 3, ini adalah nilai terkecil yang tidak digunakan.
  • Ulangi piksel b, dan konversikan nilai dalam rentang 0 hingga 4 ke karakter terkait saat mencetaknya.

Anda mungkin dapat menghemat sedikit dengan memasukkan baris kode terakhir ke dalam incrementer di forloop itu
Bukan berarti Charles
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.