薛定ding的激光


24

厌倦了对微小家畜的实验,诺贝尔奖获得者ErwinSchrödinger决定寻找最接近的激光,然后将其发射到物体上。因为……科学!

描述

您将得到两分,激光通过和激光束的大小,你必须确定激光束必须走了,可能已经走了,不能去了。

激光束可以是水平,垂直或对角线。对于1号激光束,它们分别如下所示:

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

对角激光束也可以翻转。2号激光束看起来像这样:

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

通常,要获得大小为(n)的激光束,只需获取大小为(n-1)的激光束,并在两侧添加大小为(1)的激光束。作为最后一个示例,这是所有大小为3的激光束,在同一“面板”上显示:

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

此“木板”的尺寸始终为20x20(以字符为单位)。

输入项

您的程序将获得五个整数作为输入。它们依次是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脚本生成的,这些脚本位于Stack Snippet中以节省垂直空间。

规则

  • 您的程序必须能够在30秒内(在合理的机器上)解决每个测试用例。这更像是一项健全性检查,因为我的测试Ruby程序几乎立即解决了所有测试用例。

  • 这是,因此最短的解决方案是成功的。


2
最初,这里使用的术语使我震惊。我相信激光通常是指产生激光束的设备。您在这里代表的实际上是光束,对吗?这不应该代表实际的激光,这将是产生光束的设备吗?
Reto Koradi 2015年

2
最后一个测试用例看起来不对。尺寸为4的激光器应为9像素宽。垂直轨道至少应该那么宽,但实际上更窄。
级圣河

1
@steveverrill大小4为7像素宽。以像素为单位的宽度为2 * size - 1。大小1是1像素,大小2是3像素,大小3是5像素(请参见上面的示例),大小4是7像素。
Reto Koradi

2
我不知道薛定inger与这项挑战有何关系。
user12205

1
@JonasDralle同样,时间限制主要只是一个健全性检查,几乎每个提交都可以在比之前少的时间内完成。
门把手

Answers:


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 &&回声“ 10 10 11 10 3” | 。/激光

下面是带有空格和解释性注释的相同代码:

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

输入来自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("");
  }
}

关键步骤的一些解释:

  • 数组b保存状态/结果。将为光束可以到达的所有像素设置位0。将为所有像素设置位1未被所有光束覆盖的所有。
  • 功能 f所有四个方向(垂直,水平,两个对角线)均调用该。其参数指定方向的法线向量。
  • 在功能上 f
    • 计算两个输入点相对于方向的距离(de)作为该点与传入法线向量的点积。
    • 如有必要,交换距离,使距离d始终小于或等于e
    • 如果之间有区别 de比所述光束的宽度大,没有光束在该方向上是可能的。
    • 否则,请遍历所有像素。如果像素可以被任何光束到达,则设置位0;如果未被所有光束覆盖,则设置位1。
  • 用值4标记两个输入点。由于我们使用位0和1跟踪状态,结果为0到3,因此这是最小的未使用值。
  • 循环播放中的像素b,并在打印时将0到4范围内的值转换为其相应的字符。

您可以通过在for循环中将最后一行代码放入增量器中来节省一些时间
不是查尔斯
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.