Laser di Schrödinger


24

Stufo di sperimentare piccoli animali domestici , il vincitore del premio Nobel Erwin Schrödinger ha deciso di trovare il laser più vicino e sparargli contro le cose. Perché ... scienza!

Descrizione

Ti verranno dati due punti attraverso i quali passa il laser e le dimensioni di un raggio laser, e devi determinare dove deve essere passato il raggio laser , potrebbe esserci andato e non avrebbe potuto andare.

Il raggio laser può essere orizzontale, verticale o diagonale. Per un raggio laser di dimensione 1, assomigliano rispettivamente a questo:

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

Il raggio laser diagonale può anche essere capovolto. I raggi laser di dimensione 2 si presentano così:

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

In generale, per ottenere un raggio laser di dimensioni (n), è sufficiente prendere il raggio laser di dimensioni (n-1) e aggiungere un raggio laser di dimensioni (1) su entrambi i lati. Come ultimo esempio, qui ci sono tutti i possibili raggi laser di dimensione 3, mostrati sulla stessa "scheda":

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

Questa "tavola" avrà sempre dimensioni di 20x20 (in caratteri).

Ingresso

Al tuo programma verranno dati cinque numeri interi come input. Sono, nell'ordine, x 1 , y 1 , x 2 , y 2 e le dimensioni del raggio laser. Devono essere presi esattamente in quell'ordine. Se lo si desidera, è possibile prendere le coppie ordinate (x, y) come una matrice, tupla, elenco o altro tipo di dati incorporato che memorizza due valori.

Entrambi i due punti dati come input saranno all'interno del tabellone e sono garantiti per essere distinti (cioè i due punti non saranno mai gli stessi). La dimensione del raggio laser è legata a 1 ≤ size < 20. Ci sarà sempre almeno un possibile raggio laser che attraversa entrambi i punti.

Produzione

Il tuo programma deve generare una griglia 20x20 dei seguenti caratteri:

  • # se ogni possibile raggio laser che passa attraverso i due punti attraversa anche questo punto.
  • . se non c'è raggio laser che attraversa i due punti e questo punto.
  • ? se alcuni, ma non tutti, i possibili raggi laser passano attraverso questo punto.
  • Xse questo è uno dei due punti di input originali (questo sostituisce il #).

Casi test

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

I casi di test sono stati generati con il seguente script Ruby, situato all'interno di un frammento di stack per conservare lo spazio verticale.

Regole

  • Il tuo programma deve essere in grado di risolvere ciascuno dei casi di test in meno di 30 secondi (su una macchina ragionevole). Questo è più di un controllo di integrità, poiché il mio programma di test Ruby ha risolto quasi tutti i casi di test quasi istantaneamente.

  • Questo è , quindi vince la soluzione più breve.


2
La terminologia usata qui mi ha fatto inciampare inizialmente. Credo che il laser si riferisca normalmente a un dispositivo che produce raggi laser . Quello che stai rappresentando qui sono davvero i raggi, giusto? Questa non dovrebbe essere una rappresentazione del laser reale, quale sarebbe il dispositivo che genera i raggi?
Reto Koradi,

2
L'ultimo test case sembra sbagliato. Un laser di dimensione 4 dovrebbe essere largo 9 pixel. La traccia verticale dovrebbe essere almeno così ampia, ma in realtà è più stretta.
Level River St

1
@steveverrill La dimensione 4 è larga 7 pixel. La larghezza in pixel è 2 * size - 1. La dimensione 1 è 1 pixel, la dimensione 2 è 3 pixel, la dimensione 3 è 5 pixel (vedi esempio sopra), la dimensione 4 è 7 pixel.
Reto Koradi,

2
Non vedo come Schrodinger sia legato a questa sfida.
user12205

1
@JonasDralle Anche in questo caso, il limite di tempo è per lo più solo un controllo di integrità e quasi ogni invio dovrebbe essere completato in un tempo molto inferiore a quello.
Maniglia della porta

Risposte:


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

Può essere compilato / eseguito usando:

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

Di seguito, lo stesso codice con spazi bianchi e commenti esplicativi:

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

Punti buoni. Vorrei votare se potessi!
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("");}

L'input viene preso dallo stdin, leggendo i 5 numeri nell'ordine definito.

Prima della fase di riduzione della dimensione finale:

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

Alcune spiegazioni sui passaggi chiave:

  • schieramento b contiene lo stato / il risultato. Il bit 0 verrà impostato per tutti i pixel che possono essere raggiunti da un raggio. Il bit 1 verrà impostato per tutti i pixel che non sono coperti da tutti i raggi.
  • Funzione f viene chiamata per tutte e 4 le direzioni (verticale, orizzontale, entrambe le diagonali). I suoi argomenti specificano il vettore normale della direzione.
  • In funzione f :
    • Viene calcolata la distanza di entrambi i punti di ingresso rispetto alla direzione (d e e) come prodotto punto del punto con il vettore normale passato.
    • Le distanze vengono scambiate se necessario in modo che d sia sempre inferiore o uguale a e.
    • Se la differenza tra d e eè maggiore della larghezza della trave, in questa direzione non sono possibili travi.
    • Altrimenti, passa su tutti i pixel. Impostare il bit 0 se il pixel è raggiungibile da qualsiasi raggio e il bit 1 se non è coperto da tutti i raggi.
  • Contrassegnare i due punti di input con il valore 4. Poiché abbiamo utilizzato i bit 0 e 1 per tenere traccia dello stato, che risulta nei valori da 0 a 3, questo è il valore inutilizzato più piccolo.
  • Passa sopra i pixel be converti i valori nell'intervallo da 0 a 4 nel loro carattere corrispondente mentre li stampi.

puoi probabilmente risparmiare un po 'mettendo l'ultima riga di codice nel incrementatore in quel forciclo
Non che Charles
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.