【问题标题】:The Skyline Problem‍​​天际线问题​​​
【发布时间】:2010-11-07 03:56:41
【问题描述】:

我刚刚在UVA's Online Judge 上遇到了这个小问题,并认为它可能是一个小代码高尔夫的好候选。

问题:

你要设计一个程序,帮助建筑师根据城市中建筑物的位置绘制城市的天际线。为了使问题易于处理,所有建筑物都是矩形的,并且它们共享一个共同的底部(它们所在的城市非常平坦)。这座城市也被视为二维的。建筑物由有序三元组 (Li, Hi, Ri) 指定,其中 LiRi 分别是建筑物的左右坐标i 和 Hi 是建筑物的高度。

在下图中,建筑物以三元组显示在左侧

(1,11,5), (2,6,7), (3,13,9), (12,7,16), (14,3,25), (19,18,22), (23,13,29), (24,4,28) 

右侧显示的天际线由以下序列表示:

1, 11, 3, 13, 9, 0, 12, 7, 16, 3, 19, 18, 22, 3, 23, 13, 29, 0 

输出应包含描述天际线的向量,如上例所示。在天际线向量 (v1, v2, v3, ... vn) 中,i 为偶数的 vi 表示水平线(高度)。使 i 为奇数的 vi 表示垂直线(x 坐标)。天际线矢量应该代表“路径”,例如,一个从最小 x 坐标开始并水平和垂直穿过定义天际线的所有线的错误。因此,天际线向量中的最后一个条目将是 0。坐标必须用空格分隔。

如果我不计算提供的(测试)建筑物的声明并包括所有空格和制表符,我的解决方案在 Python 中的长度为 223 个字符。

这是精简版:

B=[[1,11,5],[2,6,7],[3,13,9],[12,7,16],[14,3,25],[19,18,22],[23,13,29],[24,4,28]]

# Solution.

R=range
v=[0 for e in R(max([y[2] for y in B])+1)]
for b in B:
   for x in R(b[0], b[2]):
      if b[1]>v[x]:
         v[x]=b[1]
p=1
k=0
for x in R(len(v)):
   V=v[x]
   if p and V==0:
      continue
   elif V!=k:
      p=0
      print "%s %s" % (str(x), str(V)),
   k=V

我认为我没有犯任何错误,但如果是,请随时批评我。

我没有太多的名声,所以我只支付 100 的赏金 - 我很好奇,如果有人可以尝试在不到 .. 80 个字符的时间内解决这个问题。 cobbal 发布的解决方案是101 characters long,目前是最好的解决方案。

我想,对于这类问题,80 个字符是一个病态的限制。 cobbal,他的 46 个字符的解决方案让我非常惊讶 - 虽然我必须承认,在我部分理解他写的内容之前,我花了一些时间阅读他的解释。

【问题讨论】:

  • 这应该是维基吗?
  • 这是我在计划中实施的第一年任务。
  • 我很高兴尝试弄清楚它是如何工作的。不过,有一个小小的观察。倒数第二行可以写成:print "%s %s" % (x, V),
  • 嘿!你正在破坏玩 UVa Judge 的全部乐趣!
  • 两张图片的数据点不匹配。 (但它们确实匹配它所附带的图像。)

标签: code-golf rosetta-stone


【解决方案1】:

代码很简洁(代码几行),这对比赛很有好处(时间是最稀缺的资源),而且看起来是正确的(我不懂 python,但我想我理解代码)。

您的解决方案基本上是在缓冲区中绘制城市天际线,然后以所需格式输出缓冲区的内容。

您从问题中省略的额外信息是最多有 5000 个建筑物,并且水平位置将小于 10.000。这意味着在您的情况下内存似乎不是问题(假设 32 位架构的天际线为 40kb,建筑描述为 45kb - 可选,您可以在读取循环中绘制天际线)。该算法在建筑物数量上是线性的,因此速度很快。

如果内存限制更严格,您可以选择一次性算法,但我相信在这种情况下,它的执行速度会更慢,实现起来也更加复杂(您需要更多的时间,更多的 CPU 时间)

现在您应该考虑真正以给定格式读取输入,并使用该数据而不是预存储的数据数组进行计算。

顺便说一句,python 现在在 ACM 竞赛中是一种有效的语言吗?

【讨论】:

  • 有效语言 = Java、C、C++、C#。截至 2008 年,问题可能没有法官编写的 C# 解决方案。
  • TomatoSandwich 是对的 - Python 不是 ACM 竞赛支持的语言 - 我只是使用它,因为有了它,我可以编写精简的代码。我还省略了有关测试用例的信息,因为 SO 无法自动提供它们,所以我假设为测试数据编写的算法适用于所有数据
  • 测试数据的信息很重要。如果您的天际线坐标范围不是 10.000,而是范围为 2^32-1(最大 32 位整数),那么您的算法将有缺陷,因为它需要 2^34 字节或 16Gb 的内存来存储 v 变量(数组从 0 到2^32-1 个 32 位整数)。建筑物也是如此,如果数量足够大,您将不得不重构为一次性算法。这些都是评估算法的非常重要的项目,不仅是正确性,还有实现的可行性。
  • 帕斯卡怎么了?他们放弃了吗?
  • @fortran:据我所知,Pascal 从未加入 ACM ICPC。您可能会想到 IOI(国际信息学奥林匹克竞赛)(针对高中(大学预科)学生),其中允许的语言是 Pascal、C 和 C++。 (还没有 Java,因为碰巧在那种环境下它太慢了。)
【解决方案2】:

Python:115 个字符

与 OP 一样,我不包括数据声明,但我计算的是空格。

D = [(1,11,5), (2,6,7), (3,13,9), (12,7,16), 
 (14,3,25), (19,18,22), (23,13,29), (24,4,28)]

P=[max([0]+[h for s,h,e in D if s<=x<e])for x in range(5001)]
for i,x in enumerate(P[1:]):
   if x!=P[i]:print i+1,x,

请注意,我使用 OP 提供的链接作为问题的确切定义。例如,我假设没有超过 5000 的建筑坐标,并且所有坐标都是正整数。在我看来,原来的帖子并没有受到足够严格的限制,所以这很有趣。

编辑:感谢 John Pirie 提供的关于将列表构造折叠到打印 for 循环中的提示。我怎么会错过呢?!

edit:在决定使用原问题中给出的准确定义后,我将range(1+max(zip(*D)[2]))更改为range(5001)。第一个版本将处理任意正整数的建筑物(假设它们都适合内存)。

edit:意识到我把事情复杂化了。检查我的修订。

顺便说一句 - 我有一种预感,有一种更优雅,可能更短的方法来做到这一点。有人打我!

【讨论】:

  • 三联画,不错……真的很不错。
  • 我不太擅长 python...你假设输入是为了让它们在城市景观中还是我必须在我的代码中处理它?
  • 我不认为建筑物是按任何顺序列出的。
  • @Pirie,OP提供的原始问题的链接确实指定所有建筑物坐标都是正整数。我就这样跑了。如果没有严格定义,这个问题就没有那么有趣了。
  • @Triptych:是的,谢谢。作为一名 Python 学生,我从你的解决方案中学到了很多东西,如果我一直在搞乱它,我希望你能原谅我
【解决方案3】:

我刚刚开始学习J,所以这是我第一次尝试打高尔夫球:

103 62 49
46 个字符

   b =: 8 3 $ 1 11 5 2 6 7 3 13 9 12 7 16 14 3 25 19 18 22 23 13 29 24 4 28
   ,(,.{&s)I.s~:_1|.s=:0,~>./(1&{*{.<:[:i.{:)"1 b
1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0

虽然我确信真正了解该语言的人可以将其缩短很多

代码说明:

注意。 列出建筑物右边界的数字 ([: i. {:) 14 3 25 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 注意。 比较建筑物的左边界,然后乘以高度 (1&{ * {. <: i.>适用于 b 的每一行,注意较短的条目如何用 0 填充 (1&{ * {. <: i. b ...>折叠找到最大值,在末尾添加一个 0 以便稍后旋转,分配给 s ] s =: 0 ,~ >./ (1&{ * {. <: i. b>将 s 向右旋转 1 次,然后与 s 比较以查找高度变化的位置 s ~:_1 |。 s 0 1 0 1 0 0 0 0 0 1 0 0 1 0 0 0 1 0 0 1 0 0 1 1 0 0 0 0 0 1 注意。 找出所有差异的索引 I.s ~:_1 |。 s 1 3 9 12 16 19 22 23 29 注意。 将每个索引与那里的建筑物高度配对 (,. {&s) I. s ~: _1 |. s 1 11 3 13 9 0 ... 注意。 最后将列表展平 , (,. {&s) I. s ~: _1 |. s 1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0

【讨论】:

  • 啊,如果我看到你的改进,我就不会写下我的答案了。没想到用0自动填充,挺聪明的……
  • 有没有比这更难读的非深奥语言? ;-)
  • @Zifre:如果有需求,我可以为此写一个详细的解释,就像我为我的 J 解决方案所做的那样。一旦你习惯了 J 的词汇,这还不算太糟糕……问题是他们继承了 APL 的“每个可能的动作都必须有一个符号”并将其塞进 ASCII 中。
  • 我真的很想有一个详细的解释。看到你的第一个版本后,我下载了 J 并尝试创建自己的版本,但两分钟后我的头疼;-)
  • 我对你的解决方案有多短感到敬畏(但我还没有阅读解释)。很遗憾 J 不是提交解决方案的合格语言;我想知道你会如何在这个问题上排名。
【解决方案4】:

133个字符的Python,节省内存和时间,对数据输入没有限制

D = [(1,11,5), (2,6,7), (3,13,9), (12,7,16), (14,3,25), (19,18,22), (23,13,29), (24,4,28)]

l,T=0,zip(*D)
for x,h in map(lambda x:(x,max([y for a,y,b in D if a<=x<b]or[0])),sorted(T[0]+T[2])):
    if h!=l: print x,h,
    l=h

解释:

lambda x:(x,max([y for a,y,b in D if a<=x<b]or[0])

返回位置 x 的位置和高度。

现在循环遍历sorted(zip(*D)[0]+zip(*D)[2])编译的排序坐标列表,如果高度发生变化则输出。

第二个版本不如上面那个高效,并且有坐标限制,但只使用 115 个字符

for x in range(100):
    E=[max([y for a,y,b in D if a<=(x-i)<b]+[0])for i in(0,1)]
    if E[0]-E[1]:print x,E[0],

【讨论】:

  • 您可以在 python 中链接不等式运算符。将“a
  • 抱歉 - 在你打败我之后,我不得不重新审视我的解决方案!
【解决方案5】:

Python,89 个字符,同样使用 Triptych 的 5001 作弊:

B=[[1,11,5],[2,6,7],[3,13,9],[12,7,16],[14,3,25],[19,18,22],[23,13,29],[24,4,28]]

x=o=0
while x<5001:
 n=max([H for L,H,R in B if L<=x<R]+[0])
 if n-o:print x,n,
 o=n;x+=1

5001 替换为max(map(max,B))+1 以允许(几乎)任意大城市留下102 个字符。

修订历史:

  • 保存了两个字符,如 John Pirie 的评论中所述
  • 按照 MahlerFive 的建议保存了一个字符

【讨论】:

  • 我很敬畏。将 "L
  • 哦,是的,谢谢。这是我之前尝试的结果,我有一些理由这样做。
  • (n-o) 的忠实粉丝。我嘲笑自己使用了三个空格的缩进。干得好!
  • 使用分号使 o=n 和 x+=1 在同一行,节省 1 个字符
  • @MahlerFive:酷。老实说,我以前从未在 Python 中使用过分号。如果你问我这是否合法,我肯定不会知道。谢谢!
【解决方案6】:

98 个字符的J,默认定义(没有变量名!):

,@(([:(1:,{:"1)}.~:}:)#])@((],[:>./(1&{@[*(]>:{.@[)*]<{:@[)"1)"2 0(([:<./{."1)}.[:i.@>:[:>./{:"1))

在行动:

$ jconsole s =: ,@(([:(1:,{:"1)}.~:}:)#])@((],[:>./(1&{@[*(]>:{. @[)*]:[:>./{:"1)) |:b =: 8 3 $ 1 11 5 2 6 7 3 13 9 12 7 16 14 3 25 19 18 22 23 13 29 24 4 28 1 2 3 12 14 19 23 24 11 6 13 7 3 18 13 4 5 7 9 16 25 22 29 28 乙 1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0

只有 86 个字符,假设最左边的坐标总是 1。

,@(([:(1:,{:"1)}.~:}:)#])@((],[:>./(1&{@[*(]>:{.@[)*]<{:@[)"1)"2 0([:>:[:i.[:>./{:"1))

只有 76,另外假设最右边的坐标最多为 99。

,@(([:(1:,{:"1)}.~:}:)#])@((],[:>./(1&{@[*(]>:{.@[)*]<{:@[)"1)"2 0&(>:i.99))

借用 cobbal 的一些技巧,我可以达到 68 级。

[:,@({:"1#>:@i.@#,.{."1)[:1&|.[:(,.(~:_1&|.))[:>./(1&{*{.<:[:i.{:)"1

不过,默认定义无法与使用 s=:… 消除冗余竞争。


每当我用 J 回答问题时,我都会尝试花时间解释发生了什么,因为我认为其他人可能会喜欢了解外星语言的工作原理。

注意。向量的第一个、第二个和最后一个元素 ({. 0{b), (1 { 0{b), ({: 0{b) 1 11 5 注意。从 0 计数到(向量的最后一个元素)-1 一世。 {:0{b 0 1 2 3 4 注意。布尔值:向量的第一个元素小于或等于(以上)? ({. <:>./ (1&{*{.<: b _1>./(1&{*{.<: b>./(1&{*{.<: b>:@i.@#,.{."1) 1&|.(,.(~:_1&|.))>./(1&{*{.<: . b>:@i.@#,.{."1)1&|.(,.(~:_1&|.))>./(1&{*{.<: b>:@i.@#,.{."1)[:1&|.[:(,.(~:_1&|.))[:>./(1& {*{.<: b>

【讨论】:

  • 喜欢默契,解释也很好
【解决方案7】:

2 个 C# 答案 - 方式 太长了,但我希望看到更好的结果?

LINQ 方法(135 个字符,不包括数组行):

var a=new[]{new[]{1,11,5},new[]{2,6,7},new[]{3,13,9},new[]{12,7,16},new[]{14,3,25},new[]{19,18,22},new[]{23,13,29},new[]{24,4,28}};    
int l=0,y,x=-1;while(++x<5001){var b=a.Where(c=>c[0]<=x&&c[2]>x);if((y=b.Any()?b.Max(c=>c[1]):0)!=l)Console.Write(x+", "+(l=y)+", ");}

或非 LINQ 答案(179 个 185 字符,不包括数组行):

var a={1,11,5,2,6,7,3,13,9,12,7,16,13,3,25,19,18,22,23,13,29,24,4,28};
var b=new int[5000];int i=-1,j,z;while(++i<a.Length)for(j=a[i*3];j<a[i*3+2];j++)if((z=a[i*3+1])>b[j])b[j]=z;i=-1;z=0;while(++i<5000)if(b[i]!=z)Console.Write(i+", "+(z=b[i])+", ");

【讨论】:

  • if((y=a.Where(c=>c[0]x).Max(c=>(int?)c[1])?? 0)!=l) 为您节省几个字符
  • "Console.Write" c# 的高尔夫致命弱点 :) 在后一种解决方案中,您有 3 个对 [x,y] 的引用。替换为 [x*3+y] 需要 6 个字符,但 a.GetLength(0) 变为 a.Length。第一个 [i*3+0] 可能会丢失 th 加零,因此您可以净节省 ywo 个字符。您可以将 j 的定义提升到您定义 z 的位置。
  • 不确定是否允许自己在非 Linq 版本中使用 var,将 b 声明的一个字符剃掉。
  • 不错;随意破解其中一个/两个;-p
【解决方案8】:

这是我在 Perl 中的尝试。 137 个字符,其中 33 个字符专门用于寻找天际线的尽头。

@a = ([1,11,5],[2,6,7],[3,13,9],[12,7,16],[14,3,25],[19,18,22],[23,13,29],[24,4,28]);
($x)=sort{$b<=>$a}map{$$_[2]}@a;
for(;$c<=$x;$c++){$n=0;map{$n=$$_[1]if$c>=$$_[0]&&$c<$$_[2]&&$n<$$_[1]}@a;print"$c $n "if$n!=$h;$h=$n;}

【讨论】:

  • 它比我的还要短 :P 你花了多长时间创作的?
【解决方案9】:

重读 UVA 规则,我们不限于最大 X 5000,而是 5000 个建筑物。允许的 X 和 Y 值最高(包括)9999。

另外,显然只有 C、C++、C# 和 Java 是官方认可的语言,所以我在 Java 中完成了自己的工作。这些数字仅以空格分隔,但可以放回逗号(以多两个字符为代价)。总共 153 个字符(不包括数组行):

int[][]b=new int[][]{{1,11,5},{2,6,7},{3,13,9},{12,7,16},{14,3,25},{19,18,22},{23,13,29},{24,4,28}};
int[]y=new int[10000];int i;for(int[]o:b)for(i=o[0];i<o[2];y[i]=Math.max(y[i++],o[1]));for(i=0;i<9999;)if(y[i++]!=y[i])System.out.print(i+" "+y[i]+" ");

逻辑非常简单。唯一让流程有点不稳定的是变量重用和后增量的非标准放置。生成:

1 11 3 13 9 0 12 7 16 3 19 18 22 3 23 13 29 0 

【讨论】:

    【解决方案10】:

    一个 176 字节的 WinXP .COM 可执行文件:

    vQoAgMYQjsKO2jPAM/+5AIDzq7QLzSE8/751AXQDvoQB6DkAi/noNACL2egvACn5A/87HXYCiR2D xwLi9eviM8mZ9/VSQQvAdfeI+rQCzSG3LFqAwjC0As0h4vbD/9Y8CnP6D7bI/9Y8CnPwtACR9+UD yOvxtAvNITz/dRO0CM0hLDDDtAHNITwadfW+kAHDM/Yz/7cgrTn4dA+L+I1E/tHo6Jr/i8folf8L 9nXozSA=

    Base64 编码,我used this site to encode it。解码为 .com 文件。程序读取stdin直到一个EOF,从控制台读取时是Ctrl-Z,然后将结果输出到stdout。

    编辑:源代码:

        mov bp,10
        add dh,10h
        mov es,dx
        mov ds,dx
        xor ax,ax
        xor di,di
        mov cx,8000h
        rep stosw
        mov ah,0bh
        int 21h
        cmp al,255
        mov si,offset l9
        je l1
        mov si,offset l11
    l1:
        call l7
        mov di,cx
        call l7
        mov bx,cx
        call l7
        sub cx,di
        add di,di
    l2:
        cmp bx,[di]
        jbe l3
        mov [di],bx
    l3:
        add di,2
        loop l2
        jmp l1
    l4:
        xor cx,cx
    l5:
        cwd
        div bp
        push dx
        inc cx
        or ax,ax
        jnz l5
        mov dl,bh
        mov ah,2
        int 21h
        mov bh,44
    l6:
        pop dx
        add dl,48
        mov ah,2
        int 21h
        loop l6
        ret
    l7:
        call si
        cmp al,10
        jae l7
        db 0fh, 0b6h, 0c8h
    l8:
        call si
        cmp al,10
        jae ret
        mov ah,0
        xchg cx,ax
        mul bp
        add cx,ax
        jmp l8
    l9:
        mov ah,0bh
        int 21h
        cmp al,255
        jne l12
        mov ah,8
        int 21h
    l10:
        sub al,48
        ret
    l11:
        mov ah,1
        int 21h
        cmp al,26
        jne l10
        mov si,offset l12
        ret
    l12:
        xor si,si
        xor di,di
        mov bh,32
    l13:
        lodsw
        cmp ax,di
        je l14
        mov di,ax
        lea ax,[si-2]
        shr ax,1
        call l4
        mov ax,di
        call l4
    l14:
        or si,si
        jne l13
        int 20h
    

    像往常一样,使用 A86 编译。

    【讨论】:

    • 我怎么知道这不是木马 ;-)
    • 啊,我接管泽沃德的邪恶计划被挫败了。是时候用激光释放鲨鱼了!
    • 你的鲨鱼头上有该死的激光……太酷了
    【解决方案11】:

    这是 Perl 中的一个快速的例子

    (我指的是不到两个小时)

    只有 327 个字符的 Perl

    (不包括“ #/”以提高突出显示)

    use 5.010;
    $/=undef;
    @s=map{[split',',$_]}grep{$_}split/\)\s*(?:$|,\s*\()|^\s*\(/,<>; #/
    for$s(@s){($l,$y,$r)=@$s;
    for$x($l..$r){$c=$p[$x];$p[$x]=$c>$y?$c:$y;}}
    for($x=1;$x<=@p;$x++){$y=$p[$x]||0;
    if(!defined$z){$l=$x;$z=$y;
    }elsif($y!=$z){push@n,[$l,$z,$x-1];$z=$y;$l=$x;}}
    push@n,[$l,$z];
    say join', ',map{($_->[0],$_->[1])}@n;
    

    原测试版853个字符

    #! /usr/bin/env perl
    use strict;
    use warnings;
    use 5.010;
    use YAML;
    use List::Util 'max';
    
    
    my $file;
    {
      local $/ = undef;
      $file = <>;
    }
    
    my @sections = map { [split ',', $_] } grep {$_} split m'
      \)\s* (?:$|,\s*\() |
      ^ \s* \(
    'x, $file;
    
    #my $max_x = max map{ $_->[2] } @sections;
    #say $max_x;
    
    my @points;
    for my $reg( @sections ){
      my($l,$y,$r) = @$reg;
      for my $x ( $l .. $r ){
        my $c = $points[$x] || 0;
        $points[$x] = max $c, $y;
      }
    }
    
    
    my @new;
    my($l,$last_y);
    for( my $x=1; $x <= @points; $x++ ){
      my $y = $points[$x] || 0;
    
      # start
      if( ! defined $last_y ){
        $l = $x;
        $last_y = $y;
        next;
      }
    
      if( $y != $last_y ){
        push @new, [$l,$last_y,$x-1];
        $last_y = $y;
        $l = $x;
        next;
      }
    }
    push @new, [$l,$last_y];
    
    
    say Dump \@sections, \@points, \@new;
    
    say join ', ', map { ($_->[0],$_->[1]) } @new;
    

    初始缩小版 621 个字符

    (不包括“ #/”以提高突出显示)

    #! /usr/bin/env perl
    use strict;
    use warnings;
    use YAML;
    use 5.010;
    
    $/=undef;
    
    my@s=map{[split',',$_]}grep{$_}split/\)\s*(?:$|,\s*\()|^\s*\(/,<>; #/
    
    my@p;
    {
      no strict; no warnings 'uninitialized';
    
      for$s(@s){
        ($l,$y,$r)=@$s;
        for$x($l..$r){
          $c=$p[$x];
          $p[$x]=$c>$y?$c:$y;
        }
      }
    }
    
    # $last_y => $z
    my @n;
    {
      no strict;
    
      #my($l,$z);
      for($x=1;$x<=@p;$x++){
        $y=$p[$x]||0;
        if(!defined$z){
          $l=$x;
          $z=$y;
        }elsif($y!=$z){
          push@n,[$l,$z,$x-1];
          $z=$y;
          $l=$x;
        }
      }
      push@n,[$l,$z];
    }
    
    say Dump \@s, \@p, \@n;
    
    say join', ',map{($_->[0],$_->[1])}@n;
    

    我使用YAML 来确保我获得了正确的数据,并且不同版本的工作方式相同。

    【讨论】:

      【解决方案12】:

      除了挑战。

      结果集是否正确? 位置 22 的最高点是 18,而 23 的位置是 13,所以 3 不是最高点。

      我还尝试制作一个 php 版本,它给了我一个不同的最终向量。它没有针对速度进行优化。

      <?php
      $buildings = array(
          array(1,11,5), 
          array(2,6,7), 
          array(3,13,9), 
          array(12,7,16), 
          array(14,3,25), 
          array(19,18,22), 
          array(23,13,29), 
          array(24,4,28)
      );
      
      $preSkyline = array();
      for( $i = 0; $i<= 30; $i++){
          foreach( $buildings as $k => $building){
              if( $i >= $building[0] && $i<= $building[2]){
                  $preSkyline[$i][$k] = $building[1];
              } else{
                  $preSkyline[$i][$k] = 0;
              }
          }
      }
      foreach( $preSkyline as $s =>$a){
          $skyline[$s] = max( $a );
      }
      $finalSkyline = array();
      foreach( $skyline as $k => $v){
          if( $v !== $skyline[ $k-1]){
              $finalSkyline[$k] =  $v;
          }
      }
      echo "<pre>";
      print_r( $finalSkyline );
      ?>
      

      返回:

      Array
      (
          [0] => 11
          [2] => 13
          [9] => 0
          [11] => 7
          [16] => 3
          [18] => 18
          [22] => 13
          [29] => 0
      )
      

      是拐点和最大高度。

      【讨论】:

        【解决方案13】:

        假设输入:

        b=[(1,11,5),(2,6,7),(3,13,9),(12,7,16),(14,3,25),(19,18,22),(23,13,29),(24,4,28)]
        

        Haskell:105 个字符

        h x=maximum$0:[y|(l,y,r)<-b,l<=x,x<r]
        main=putStr$unwords[show x++" "++show(h x)|x<-[1..9999],h x/=h(x-1)]
        

        字符串格式化似乎是 Haskell 落后于 Python 解决方案的地方。必须使用额外的 5 个字符来编写 'main=' 也无济于事,但也许不应该包括在内,如果 C#/Java 解决方案的代码必须演示完整的程序,那将是巨大的:)

        Haskell:76 个字符 (无字符串格式和无主)

        h x=maximum$0:[y|(l,y,r)<-b,l<=x,x<r]
        print[(x,h x)|x<-[1..9999],h x/=h(x-1)]
        

        回顾original problem,它要求您从文件中读取输入,所以我认为看看增加了多少字符会很有趣。

        Haskell:149 个字符(完整解决方案)

        main=interact f
        f i=unwords[show x++" "++show(h x)|x<-[1..9999],h x/=h(x-1)] where
         h x=maximum$0:[y|[l,y,r]<-b,l<=x,x<r]
         b=map(map read.words)$lines i
        

        下面是完整解决方案的样子,尽可能提供更具描述性的变量名称和类型签名。

        main :: IO ()
        main = interact skyline
        
        skyline :: String -> String
        skyline input =
        
          unwords [show x ++ " " ++ show (heightAt x) |
                   x <- [1..9999], heightAt x /= heightAt (x-1)]
        
          where heightAt :: Int -> Int
                heightAt x = maximum $ 0 : [h | [l,h,r] <- buildings, l <= x, x < r]
        
                buildings :: [[Int]]
                buildings = map (map read . words) $ lines input
        

        【讨论】:

          【解决方案14】:

          红宝石,80 个字符

          B=[[1,11,5],[2,6,7],[3,13,9],[12,7,16],[14,3,25],[19,18,22],[23,13,29],[24,4,28]]
          o=0;1.upto(5001){|x|y=(B.map{|b|x>=b[0]&&x<b[2]&&b[1]||0}.max);o!=(o=y)&&p(x,y)}
          

          【讨论】:

            【解决方案15】:

            C

            int main(int arc, char **argv) {
              int B[][3]={{1,11,5},{2,6,7},{3,13,9},{12,7,16},{14,3,25},{19,18,22},{23,13,29},{24,4,28}},o=0,y=0,x=0,blen=8,bs=0,b;
              for (;x<9001;x++,o=y,y=0) {
                for (b=bs;b<blen;b++) {
                  if (x >= B[b][0] && x < B[b][2] && B[b][1] > y) y=B[b][1];
                  if (x > B[b][2]) bs = b;
                }
                if (y-o) printf("%d %d ", x, y);
              }
            }
            

            【讨论】:

              【解决方案16】:
              #include <stdio.h>
              #define MAX_B   5000
              static unsigned max_y[MAX_B];
              main() {
                  signed i, j;
                  int max_x = 0, last_new = 0, curr_ht = 0;
              
                  for (;!feof(stdin);) {
                      int l, h, r;
                      fscanf(stdin, "%d %d %d\n", &l, &h, &r);
                      if (r > max_x)
                          max_x = r;
                      for (i = l; i <= r; i++)
                          if (max_y[i] < h)
                              max_y[i] = h;
                  }
                  max_x += 2;
                  for (i = 0; i < max_x; i++) {
                      j = max_y[i] - last_new;
                      curr_ht += j;
                      last_new = max_y[i];
                      if (j > 0)
                          printf("%d %d ", i, curr_ht);
                      if (j < 0)
                          printf("%d %d ", i - 1, curr_ht);
                  }
                  printf("\n");
              }
              

              非常简单的 C 解决方案...540 个字符。

              【讨论】:

                【解决方案17】:

                尽管这是一篇旧文章,但我想我会用 137 个字符分享我的 gnu octave 实现:

                function[p]=sl(b)s=zeros(max(b)(:,2),max(b(:,3)));for i=b's(1:i(2),i(1):i(3)-1)=1;end;t=sum(s);u=find(shift(t,1)~=t);p=[u;t(u)](:)';end;
                

                将任意大小的三元组矩阵传递为b

                【讨论】:

                  猜你喜欢
                  • 2011-03-13
                  • 2015-09-13
                  • 2013-02-05
                  • 1970-01-01
                  • 2018-09-11
                  • 1970-01-01
                  • 1970-01-01
                  • 2014-04-18
                  • 1970-01-01
                  相关资源
                  最近更新 更多