Лазер Шредингера


24

Надоело экспериментировать на крошечных домашних животных , лауреат Нобелевской премии Эрвин Шредингер решил найти ближайший лазер и вместо этого выстрелить в него. Потому что ... наука!

Описание

Вам дадут две точки, через которые проходит лазер, и размер лазерного луча, и вы должны определить, куда лазерный луч должен был уйти, мог бы уйти и не мог бы уйти.

Лазерный луч может быть горизонтальным, вертикальным или диагональным. Для лазерного луча размера 1 они выглядят следующим образом:

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

Диагональный лазерный луч также можно перевернуть. Лазерные лучи размера 2 выглядят так:

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

В общем, чтобы получить лазерный луч размера (n), просто возьмите лазерный луч размера (n-1) и добавьте лазерный луч размера (1) с обеих сторон. В качестве последнего примера, здесь представлены все возможные лазерные лучи размером 3, показанные на одной и той же «доске»:

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

Эта «доска» всегда будет иметь размеры 20х20 (в символах).

вход

Ваша программа получит пять целых чисел в качестве входных данных. Они по порядку: x 1 , y 1 , x 2 , y 2 и размер лазерного луча. Они должны быть приняты именно в таком порядке. При желании вы можете использовать упорядоченные пары (x, y) в качестве массива, кортежа, списка или другого встроенного типа данных, в котором хранятся два значения.

Обе эти две точки, указанные в качестве входных данных, будут находиться внутри доски, и они гарантированно будут отличаться (т.е. две точки никогда не будут одинаковыми). Размер лазерного луча связан с 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, расположенного внутри фрагмента стека для сохранения вертикального пространства.

правила

  • Ваша программа должна быть в состоянии решить каждый из тестовых случаев менее чем за 30 секунд (на приемлемой машине). Это скорее проверка работоспособности, так как моя тестовая программа Ruby решила все тесты практически мгновенно.

  • Это , поэтому выигрывает самое короткое решение.


2
Терминология, использованная здесь, сначала сбила меня с толку. Я считаю, что лазер обычно относится к устройству, которое производит лазерные лучи . То, что вы представляете здесь, действительно лучи, верно? Это не должно быть представление фактического лазера, который будет устройством, генерирующим лучи?
Рето Коради

2
Последний тестовый пример выглядит неправильно. Лазер размера 4 должен иметь ширину 9 пикселей. Вертикальная дорожка должна быть как минимум такой широкой, но на самом деле она уже.
Уровень Река St

1
@steveverrill Размер 4 составляет 7 пикселей в ширину. Ширина в пикселях равна 2 * size - 1. Размер 1 - 1 пиксель, размер 2 - 3 пикселя, размер 3 - 5 пикселей (см. Пример выше), размер 4 - 7 пикселей.
Рето Коради

2
Я не понимаю, как Шредингер связан с этой проблемой.
user12205

1
@JonasDralle Опять же, ограничение по времени - это в основном проверка работоспособности, и ожидается, что почти каждая отправка будет завершена за гораздо меньшее время.
Дверная ручка

Ответы:


5

C 291 280 277 265 байт

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 laser && 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

Хорошие моменты. Я бы проголосовал, если бы мог!
Андре Хардер

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

Входные данные взяты из стандартного ввода, читая 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("");
  }
}

Некоторое объяснение ключевых шагов:

  • Массив bсодержит состояние / результат. Бит 0 будет установлен для всех пикселей, которые могут быть достигнуты лучом. Бит 1 будет установлен для всех пикселей, которые не покрыты всеми лучами.
  • Функция fвызывается для всех 4 направлений (вертикальное, горизонтальное, обе диагонали). Его аргументы указывают вектор нормали направления.
  • В функции f:
    • Расстояние между обеими входными точками относительно направления рассчитывается ( dи e) как произведение точек на точку, в которую передан вектор нормали.
    • При необходимости расстояния меняются местами, так что они dвсегда меньше или равны e.
    • Если разница между dи eбольше ширины луча, лучи в этом направлении невозможны.
    • В противном случае, обведите все пиксели. Установите бит 0, если пиксель доступен любым лучом, и бит 1, если он не покрыт всеми лучами.
  • Отметьте две входные точки значением 4. Поскольку мы использовали биты 0 и 1 для отслеживания состояния, что приводит к значениям от 0 до 3, это наименьшее неиспользуемое значение.
  • Зацикливайте пиксели внутри bи преобразуйте значения в диапазоне от 0 до 4 в соответствующие им символы при их распечатке.

скорее всего, вы можете немного сэкономить, поместив последнюю строку кода в инкрементатор в этом forцикле
не то, что Чарльз
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.