用激光摧毁他们


21

介绍

竞技场是点缀着摩天大楼的平地,您的敌人可以用来掩盖。您和您的敌人用激光互相射击。你们所有人都携带喷气背包,可以飞行。

您可以用激光打哪些敌人,哪些可以躲藏?

问题

首先,竞技场的大小由n单行中的整数给出。以下各nn每行包含整数,并用空格分隔。每个整数代表该位置建筑物的高度。每个建筑物都是一个矩形实体,高度单位为1单位乘1单位。

接下来,您的位置是在一行三个浮点数给出xyz

最后,敌人的数量由m单行中的整数给出。以下各m行每行包含三个浮点数,中间用空格隔开。这些代表 xy以及z敌人的坐标。坐标系定义如下:

  • x 在城市输入中从左到右测量
  • y 从上到下测量
  • z 从头开始测量

对于每个敌人,如果可以从您到该敌人画出一条清晰的线,则输出一个整数。否则,输出一个整数。用新行分隔输出。

样本输入

注释以“#”表示,可帮助您快速查看每一行的功能。它们将不会出现在实际输入中。

5              # Size of the map
0 0 0 0 0      # Buildings
0 0 0 0 0      # Buildings
4 4 4 4 4      # Buildings
0 0 0 0 0      # Buildings
0 0 0 0 0      # Buildings
2.5 0.0 4.0    # Your location
3              # Number of enemies
2.5 5.0 0.1    # Enemy location
2.5 5.0 5.0    # Enemy location
0.0 2.7 4.5    # Enemy location

样品输出

对于上面的示例输入,我们输出以下内容:

-1
1
1

假设条件

  • 0 n<<100
  • 0 m<<100
  • 0 <= x<=n
  • 0 <= y<=n
  • 0 <= z<n
  • 玩家不会位于建筑物的角落,边缘或侧面上或内部
  • 您对敌人的视线永远不会与建筑物的拐角,边缘或侧面相切
  • 玩家不是障碍

很高兴
能从

7
如果我不能消灭敌人,我可以加入他们吗?
约翰·德沃夏克

@ user80551抱歉,由于拼写是故意的,我不得不将您的编辑回滚到标题。去谷歌上查询。
Rainbolt 2014年

@Rusher哦,对不起,IDK
user80551 2014年

Answers:


5

Perl中,301 296 282

编辑2:其实,不管是否参加比赛,没有理由不让高尔夫运动得更远。在线测试。

编辑:一对括号不见了,更简单的正则表达式检查非零整数。

带有换行符和缩进以提高可读性:

sub i{<>=~/\S+/g}
@b=map[i],@r=0..<>-1;
print.1<=>(map{
    @a[1,0,2,4,3]=@a;
    @b=map{$i=$_;[map$b[$_][$i],@r]}@r;
    grep$a[3]
        &&($k=(($x=$_)-$a[0])/$a[3])**2<=$k
        &&pop[sort map@{$b[$_]}[$x-!!$x,$x],
                   ($_=$a[1]+$k*$a[4]),$_-/^\d+$/]
           >=$a[2]+$k*$a[5]
    ,@R=@r
}@a=map$_-shift@v,i,@u=@v=@$_),$/for([i])x<>

它需要5.14,因为标量(数组引用)参数来的pop


您能否解释一下您的解决方案?我还没有进行测试,也没有Perl的经验,所以有些评论是不错的。
WorldSEnder 2014年

@WorldSEnder,算法概述如下。直线PE连接3-D空间中的两个点,即“玩家”(X1Y1Z1)和“敌人”(X2Y2Z2)。它在(XY)平面上的投影与某些网格线相交,即整数x = consty = const诸如X1 < x < X2Y1 < y < Y2(在此假设,例如X1 < X2,但并不重要)。x y这些交点的坐标很容易找到,因此线上z的点的坐标也很容易找到PE
user2846289 2014年

(续)另一方面,对于任何x y坐标,我们都知道h建筑物的高度(确切地说,最多四个共享x y点的建筑物的最大高度)。当(且仅当)h < z上述所有“交叉点” 都可以射击敌人。实现是一些基本的算法,以及出于打高尔夫球目的使用Perl的一些技巧。解密一个月前我的操作方式的细节现在将花费一些时间:-)。
user2846289 2014年

抱歉,我看到上一个(第5个)修订版中存在一个错误:表达式中@a数组元素的索引grep应按顺序出现,0,3,0,4,1,5,2而不是3,0,3,1,4,2,5-对不起。
user2846289 2014年

好吧,迟到总比没有好,并且要结束所有这些,这里是带注释的版本。
user2846289 2014年

3

Python 2.7版- 429 420 308 308个字符

我认为这个挑战更多是数学问题,而不是代码高尔夫球问题,因此,如果我错过了一些明显的优化,对我来说不要太苛刻。无论如何,这是代码:

b=lambda:raw_input().split()
m=map
d=range(input())
h=[m(int,b())for _ in d]
x,y,z=m(float,b())
for e,f,g in[m(float,b())for _ in[1]*input()]:o=lambda x,y,u,v,i,j:i<=x+u/v*(j+1-y)<=i+1<[]>z+(g-z)/v*(j+1-y)<=max(h[i][j:j+2])if v else 0;print 1-2*any(o(x,y,e-x,f-y,j,i)+o(y,x,f-y,e-x,i,j)for j in d for i in d)

这应该适用于边缘和角落情况(意外的双关语),并且非常牢固。提供的示例的输出:

-1
1
1

这是一个“简短”的解释:

fast_read = lambda : raw_input().split() # define a helper
# m = map another helper
grid_range = range(input())
houses = [map(int, fast_read()) for _ in grid_range]
# 'map(int,...)' is a shorter version of '[int(a) for a in ...]'
pos_x,pos_y,pos_z = map(float, fast_read()) # read the player position
# the following loops through all enemy coordinates
for ene_x, ene_y, ene_z in [map(float,fast_read()) for _ in[1]*input()]:
    vec_z = ene_z - pos_z
    # is_hit macro uses vector math to detemine whether we hit a specific wall
    # wallhit -> 1
    # no wallhit -> 0
    is_hit = lambda pos_x, pos_y, vec_x, vec_y, co_x, co_y:\
        (co_x <= pos_x + vec_x/vec_y * (co_y + 1 - pos_y) <= co_x + 1 # check if hit_x is good
        < [] > # an effective and
        pos_z + (ene_z - pos_z)/vec_y * (co_y + 1 - pos_y) <= max(houses[co_x][co_y:co_y + 2]) # check if hit_z is good
        if vec_y else 0) # if vec_y is 0 we can't hit the wall parallel to y
    print (.5 - # can hit -> 0.5 - 0 = 0.5, hit -> 0.5 - 1 = -0.5
            any( # if we hit any wall
                # we swap x and y-coordinate because we read them "incorrect"
                is_hit(pos_x, pos_y, ene_x-pos_x, ene_y-pos_y, cur_y, cur_x) # check for hit in x-direction
                + # effective 'or'
                is_hit(pos_y, pos_x, ene_y-pos_y, ene_x-pos_x, cur_x, cur_y) # check for hit in y-direction
                    for cur_y in grid_range # loop y
                for cur_x in grid_range)) # loop x

我猜这充满了缺陷。顺便说一句,我在嵌套时保存了字符(第一级是一个空格,第二个是一个标签,然后是一个标签和一个空格...)。我希望所有这些答案都可以指出这样做的方法。


我只是意识到样本输入无效,因为其中一个敌人直接位于地面上,从技术上讲,这是零高度建筑物的顶部,我保证不会发生。您的提交通过了更正的测试用例,但未通过此one-ideone.com/8qn3sv。你可以检查我的测试用例吗?我可能丢失了一些东西,或者坐标系统不清楚。
Rainbolt 2014年

不,只是向量正在转弯...现在我知道你为什么要承诺6&7了:)
WorldSEnder 2014年

顺便说一句,我输出了一个负浮点数,但是可以用2个额外的字符(print 1-2*...而不是print.5-...)来解决,所以我猜它的差别并不大
WorldSEnder 2014年

您通过了我提出的一些测试。不错的工作!您仍应继续操作,并使其打印整数以符合规范。
Rainbolt 2014年

1
接受您的答案,直到有人提出更好的解决方案。我认为他们不会。很少有人会重温以前解决的挑战。你应该打更多的高尔夫球!看来您知道自己的东西。:)
雨栓

2

C-2468

根本不打高尔夫,但希望这是更有趣的实现的起点。实施intersectAdrian Boeing严重削弱了。他的伪代码不完整,但是他对数学的解释非常宝贵。基本思想是,您从玩家到目标之间划一条线,并将其夹在每栋建筑物的所有墙壁上,从而更新每面墙壁的长度。剩余长度是建筑物内部的一部分,因此如果长度为零,则没有交集。

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

typedef struct
{
    float x;
    float y;
    float z;
} vec3;

float
dot(vec3 a, vec3 b)
{
    return a.x * b.x + a.y * b.y + a.z * b.z;
}

vec3
scale(float s, vec3 a)
{
    vec3 r;
    r.x = s * a.x;
    r.y = s * a.y;
    r.z = s * a.z;
    return r;
}

vec3
add(vec3 a, vec3 b)
{
    vec3 r;
    r.x = a.x + b.x;
    r.y = a.y + b.y;
    r.z = a.z + b.z;
    return r;
}

int
intersect(vec3 a, vec3 b, vec3 *normals, vec3 *points, int nnormals)
{
    vec3 ab = add(b, scale(-1, a));
    float tfirst = 0;
    float tlast = 1;
    int i;
    for(i = 0; i < nnormals; i++)
    {
        float d = dot(normals[i], points[i]);
        float denom = dot(normals[i], ab);
        float dist = d - dot(normals[i], a);
        float t = dist / denom;
        if(denom > 0 && t > tfirst)
        {
            tfirst = t;
        }
        else if(denom < 0 && t < tlast)
        {
            tlast = t;
        }
    }
    return tfirst < tlast ? 1 : 0;
}

const vec3 N = {0,-1,0};
const vec3 S = {0,1,0};
const vec3 W = {-1,0,0};
const vec3 E = {1,0,0};
const vec3 D = {0,0,-1};

int
main(void)
{
    vec3 normals[5];
    vec3 player;
    vec3 *targets;
    int i;
    int j;
    vec3 *buildings;
    vec3 *b;
    int nbuildings = 0;
    int n;
    int m;
    char line[300];
    normals[0] = N;
    normals[1] = S;
    normals[2] = W;
    normals[3] = E;
    normals[4] = D;
    fgets(line, 300, stdin);
    n = atoi(line);
    /*5 sides for each building*/
    buildings = calloc(n * n * 5, sizeof(*buildings));
    b = buildings;
    for(i = 0; i < n; i++)
    {
        char *z;
        fgets(line, 300, stdin);
        for(j = 0; j < n && (z = strtok(j ? NULL : line, " \n")) != NULL; j++)
        {
            vec3 bottom;
            vec3 top;
            if(z[0] == '0') continue;
            nbuildings++;
            bottom.x = j;
            bottom.y = i;
            bottom.z = 0;
            top.x = j + 1;
            top.y = i + 1;
            top.z = atoi(z);
            b[0] = top;
            b[1] = bottom;
            b[2] = top;
            b[3] = bottom;
            b[4] = top;
            b += 5;
        }
    }
    fgets(line, 300, stdin);
    player.x = atof(strtok(line, " "));
    player.y = atof(strtok(NULL, " "));
    player.z = atof(strtok(NULL, " \n"));
    fgets(line, 300, stdin);
    m = atoi(line);
    targets = calloc(m, sizeof(*targets));
    for(i = 0; i < m; i++)
    {
        int hit = 1;
        fgets(line, 300, stdin);
        targets[i].x = atof(strtok(line, " "));
        targets[i].y = atof(strtok(NULL, " "));
        targets[i].z = atof(strtok(NULL, " \n"));
        for(j = 0; j < nbuildings; j++)
        {
            b = &buildings[j * 5];
            if(intersect(player, targets[i], normals, b, 5) == 1)
            {
                hit = 0;
                break;
            }
        }
        printf("%d\n", hit ? 1 : -1);
    }
    free(buildings);
    free(targets);
    return 0;
}

尝试了一些测试用例,您都通过了所有测试。这是其他任何人都可以用来验证的ideone-ideone.com/MTXpzF
Rainbolt
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.