เลเซอร์ของSchrödinger


24

เบื่อหน่ายกับการทดลองกับสัตว์เลี้ยงตัวเล็ก ๆ Erwin Schrödingerที่ได้รับรางวัลโนเบลได้ตัดสินใจที่จะหาเลเซอร์ที่ใกล้ที่สุดแล้วยิงมันที่สิ่งของแทน เพราะ ... วิทยาศาสตร์!

ลักษณะ

คุณจะได้รับสองจุดที่เลเซอร์ผ่านและขนาดของลำแสงเลเซอร์และคุณจะต้องตรวจสอบที่ลำแสงเลเซอร์จะต้องได้ไปจะได้หายไปและไม่สามารถมีหายไป

ลำแสงเลเซอร์สามารถเป็นแนวนอนแนวตั้งหรือแนวทแยง สำหรับลำแสงเลเซอร์ขนาด 1 พวกมันมีลักษณะดังนี้:

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

ลำแสงเลเซอร์ทแยงมุมสามารถพลิกได้ ลำแสงเลเซอร์ขนาด 2 มีลักษณะดังนี้:

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

โดยทั่วไปเพื่อให้ได้ลำแสงเลเซอร์ขนาด (n) เพียงนำลำแสงเลเซอร์ขนาด (n-1) และเพิ่มลำแสงเลเซอร์ขนาด (1) ทั้งสองด้าน เป็นตัวอย่างขั้นสุดท้ายต่อไปนี้เป็นลำแสงเลเซอร์ที่เป็นไปได้ขนาด 3 ทั้งหมดที่แสดงบน "บอร์ด" เดียวกัน:

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

"บอร์ด" นี้จะมีขนาด 20x20 (เป็นตัวอักษร)

อินพุต

โปรแกรมของคุณจะได้รับห้าจำนวนเต็มเป็นอินพุท ตามลำดับ x 1 , y 1 , x 2 , y 2และขนาดของลำแสงเลเซอร์ พวกเขาจะต้องดำเนินการอย่างถูกต้องในลำดับที่ หากคุณต้องการคุณอาจใช้คู่ที่สั่งซื้อ (x, y) เป็นอาร์เรย์ tuple รายการหรือชนิดข้อมูลในตัวอื่น ๆ ที่เก็บค่าสองค่า

ทั้งสองจุดที่ให้เป็นอินพุตจะอยู่ในบอร์ดและรับประกันว่าจะชัดเจน (เช่นสองคะแนนจะไม่เหมือนเดิม) 1 ≤ size < 20ขนาดของลำแสงเลเซอร์ที่ถูกผูกไว้ จะมีลำแสงเลเซอร์ที่เป็นไปได้อย่างน้อยหนึ่งจุดที่ลอดผ่านจุดทั้งสอง

เอาท์พุต

โปรแกรมของคุณจะต้องส่งออกตาราง 20x20 ของตัวละครต่อไปนี้:

  • # หากลำแสงเลเซอร์ที่เป็นไปได้ทุกจุดที่ผ่านจุดสองจุดนั้นผ่านจุดนี้ด้วย
  • . หากไม่มีลำแสงเลเซอร์ที่ผ่านจุดสองจุดและจุดนี้
  • ? ถ้ามีลำแสงเลเซอร์ที่เป็นไปได้บางส่วน แต่ไม่ใช่ทั้งหมดผ่านจุดนี้
  • Xหากนี่เป็นหนึ่งในสองจุดอินพุตดั้งเดิม (นี่จะแทนที่#)

กรณีทดสอบ

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??????.....
..??????????????....
..???????????????...
..????????????????..
..?????????????????.
..??????????????????
..??????????????????
..????????.?????????
..????????..????????
..????????...???????

กรณีทดสอบถูกสร้างขึ้นด้วยสคริปต์ Ruby ต่อไปนี้ซึ่งอยู่ภายใน Stack Snippet เพื่อประหยัดพื้นที่ในแนวตั้ง

กฎระเบียบ

  • โปรแกรมของคุณจะต้องสามารถแก้ไขกรณีทดสอบแต่ละรายการในเวลาไม่เกิน 30 วินาที (ในเครื่องที่เหมาะสม) นี่คือการตรวจสุขภาพจิตที่มากขึ้นเนื่องจากโปรแกรมการทดสอบ Ruby ของฉันแก้ไขกรณีทดสอบทั้งหมดใกล้ทันที

  • นี่คือดังนั้นทางออกที่สั้นที่สุดชนะ


2
คำศัพท์ที่ใช้ที่นี่ทำให้ผมสะดุดในตอนแรก ผมเชื่อว่าเลเซอร์ปกติหมายถึงอุปกรณ์ที่ผลิตลำแสงเลเซอร์ สิ่งที่คุณเป็นตัวแทนที่นี่คือคานจริง ๆ ใช่มั้ย นี่ไม่ควรจะเป็นตัวแทนของเลเซอร์จริงซึ่งจะเป็นอุปกรณ์ที่สร้างลำแสง?
Reto Koradi

2
กรณีทดสอบล่าสุดดูไม่ถูกต้อง เลเซอร์ขนาด 4 ควรมีความกว้าง 9 พิกเซล แทร็กแนวตั้งควรกว้างอย่างน้อยนั้น แต่อันที่จริงแล้วแคบกว่า
เลเวลริเวอร์เซนต์

1
@steveverrill ขนาด 4 กว้าง 7 พิกเซล 2 * size - 1ความกว้างพิกเซลคือ ขนาด 1 คือ 1 พิกเซลขนาด 2 คือ 3 พิกเซลขนาด 3 คือ 5 พิกเซล (ดูตัวอย่างด้านบน) ขนาด 4 คือ 7 พิกเซล
Reto Koradi

2
ฉันไม่เห็นว่า Schrodinger เกี่ยวข้องกับความท้าทายนี้อย่างไร
user12205

1
@JonasDralle อีกครั้งการ จำกัด เวลาส่วนใหญ่เป็นเพียงการตรวจสติและเกือบทุกการส่งนั้นคาดว่าจะเสร็จสมบูรณ์ในเวลาที่น้อยกว่านั้น
Doorknob

คำตอบ:


5

C, 291 280 277 265 bytes

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

สามารถรวบรวม / เรียกใช้โดยใช้:

gcc laser.c -o เลเซอร์ && echo "10 10 11 10 3" | ./laser

ด้านล่างโค้ดเดียวกันกับช่องว่างและความคิดเห็นอธิบาย:

// 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

จุดที่ดี ฉันจะลงคะแนนถ้าฉันทำได้!
André Harder

4

C, 302 ไบต์

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

อินพุตถูกนำมาจาก stdin โดยอ่านตัวเลข 5 ตัวตามลำดับที่กำหนด

ก่อนขั้นตอนการลดขนาดขั้นสุดท้าย:

#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("");
  }
}

คำอธิบายบางส่วนของขั้นตอนสำคัญ:

  • Array bมีสถานะ / ผลลัพธ์ บิต 0 จะถูกตั้งค่าสำหรับพิกเซลทั้งหมดที่สามารถเข้าถึงได้โดยคาน บิต 1 จะถูกตั้งค่าสำหรับพิกเซลทั้งหมดที่ไม่ได้รับการครอบคลุมโดยคานทั้งหมด
  • ฟังก์ชั่นfถูกเรียกใช้สำหรับทั้ง 4 ทิศทาง (แนวตั้ง, แนวนอน, แนวทแยงมุมทั้งสอง) อาร์กิวเมนต์ของมันระบุเวกเตอร์ปกติของทิศทาง
  • ในฟังก์ชั่นf:
    • ระยะห่างของจุดอินพุตทั้งสองที่สัมพันธ์กับทิศทางจะถูกคำนวณ ( dและe) เป็นผลิตภัณฑ์ดอทของจุดที่มีเวกเตอร์ปกติส่งผ่าน
    • ระยะทางที่จะสลับหากดังนั้นจำเป็นที่เสมอน้อยกว่าหรือเท่ากับde
    • หากความแตกต่างระหว่างdและeมีขนาดใหญ่กว่าความกว้างของคานจะไม่มีความเป็นไปได้ในทิศทางนี้
    • มิฉะนั้นวนรอบพิกเซลทั้งหมด ตั้งค่าบิต 0 หากพิกเซลสามารถเข้าถึงได้โดยลำแสงใด ๆ และบิต 1 หากไม่ได้ครอบคลุมคานทั้งหมด
  • ทำเครื่องหมายจุดอินพุตสองจุดด้วยค่า 4 เนื่องจากเราใช้บิต 0 และ 1 เพื่อติดตามสถานะซึ่งส่งผลให้ค่า 0 ถึง 3 นี่คือค่าที่ไม่ได้ใช้น้อยที่สุด
  • วนรอบพิกเซลเข้าbและแปลงค่าในช่วง 0 ถึง 4 เป็นอักขระที่สอดคล้องกันในขณะที่พิมพ์ออกมา

คุณน่าจะประหยัดได้เล็กน้อยโดยใส่รหัสบรรทัดสุดท้ายลงในตัวเพิ่มในforลูปนั้น
ไม่ใช่ที่ Charles
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.