您可以看到多少座塔?


29

该问题基于数字放置拼图塔(也称为摩天大楼),您可以在网上玩。您的目标是解决难题并确定线索-沿每一行和每一列可见的塔数。这是代码高尔夫,所以最少的字节获胜。

塔如何运作

塔难题的解决方案是一个拉丁方-一个n*n网格,每一行和每一列都包含1贯穿的数字排列n。以下n=5是一个示例:

4 3 5 2 1 
5 4 1 3 2 
1 5 2 4 3 
2 1 3 5 4 
3 2 4 1 5 

每行和每一列的两端都标有线索,例如:

       2 3 1 4 5    
       v v v v v

 2 >   4 3 5 2 1   < 3
 1 >   5 4 1 3 2   < 4
 2 >   1 5 2 4 3   < 3
 3 >   2 1 3 5 4   < 2
 3 >   3 2 4 1 5   < 1 

       ^ ^ ^ ^ ^
       2 2 2 2 1

每个线索都是从1到的数字n,告诉您从该方向沿着行/列看时“看到”的塔数,如果这些数字被视为具有该高度的塔。每个塔都在其后挡住了较短的塔。换句话说,您可以看到的塔楼比之前的任何塔楼都要高。

图片来自Conceptis Puzzles

例如,让我们看第一行。

 2 >   4 3 5 2 1   < 3

它具有2从左开始的线索,因为您可以看到45。该43从视线和5块一切。从右边,你可以看到3塔:12,和5

计划要求

编写一个程序或函数,该程序或函数接受数字的网格并从左上角开始按顺时针方向输出或打印提示。

输入值

带的n*n拉丁方2<=n<=9

格式灵活。您可以使用任何表示包含数字或数字字符的网格或列表的数据结构。您可能需要在行之间使用分隔符,或者根本不需要分隔符。一些可能性是列表,列表列表,矩阵,令牌分隔的字符串,例如

43521 54132 15243 21354 32415,

或没有空格的字符串。

您没有n作为输入的一部分。

输出量

从左上角开始按顺时针方向返回或打印线索。因此,首先是上部提示向右阅读,然后是右提示向下阅读,然后是下部提示向左阅读,而左侧提示则向上阅读。

这将是23145 34321 12222 33212前面的示例

       2 3 1 4 5    
       v v v v v

 2 >   4 3 5 2 1   < 3
 1 >   5 4 1 3 2   < 4
 2 >   1 5 2 4 3   < 3
 3 >   2 1 3 5 4   < 2
 3 >   3 2 4 1 5   < 1 

       ^ ^ ^ ^ ^
       2 2 2 2 1

就像输入一样,您可以使用列表,字符串或任何有序结构。四个“组”可以嵌套或平面结构分开或不分开。但是,每个组的格式必须相同。

测试用例示例:

(您的输入/输出格式不必与此相同。)

>> [[1 2] [2 1]]

[2 1]
[1 2]
[2 1]
[1 2]

>> [[3 1 2] [2 3 1] [1 2 3]]

[1 2 2]
[2 2 1]
[1 2 3]
[3 2 1]

>> [[4 3 5 2 1] [5 4 1 3 2] [1 5 2 4 3] [2 1 3 5 4] [3 2 4 1 5]]

[2 3 1 4 5]
[3 4 3 2 1]
[1 2 2 2 2]
[3 3 2 1 2]

>> [[2 6 4 1 3 7 5 8 9] [7 2 9 6 8 3 1 4 5] [5 9 7 4 6 1 8 2 3] [6 1 8 5 7 2 9 3 4] [1 5 3 9 2 6 4 7 8] [3 7 5 2 4 8 6 9 1] [8 3 1 7 9 4 2 5 6] [9 4 2 8 1 5 3 6 7] [4 8 6 3 5 9 7 1 2]]

[4 2 2 3 3 3 3 2 1]
[1 3 3 2 2 2 2 3 3]
[4 3 2 1 2 3 3 2 2]
[3 1 2 4 3 3 2 2 5]

为方便起见,以下是相同的测试用例,采用扁平字符串格式。

>> 1221

21
12
21
12

>> 312231123

122
221
123
321

>> 4352154132152432135432415

23145
34321
12222
33212

>> 264137589729683145597461823618572934153926478375248691831794256942815367486359712

422333321
133222233
432123322
312433225

Answers:


22

APL 19

≢¨∪/⌈\(⍉⍪⌽⍪⊖∘⌽∘⍉⍪⊖)

(在ngn的建议后再打高尔夫球,谢谢)

说明:

(⍉⍪⌽⍪⊖∘⌽∘⍉⍪⊖)  rotates matrix 4 times appending results
⌈\ gets maximums for each row up to current column (example: 4 2 3 5 1 gives 4 4 4 5 5)
≢¨∪/ counts unique elements for each row

tryapl.org尝试


1
您可以避免添加1:≢¨∪¨↓⌈\(⍉⍪⌽⍪⍉∘⌽∘⊖⍪⊖)
ngn 2014年

@ngn你是对的,谢谢!我还应用了∪/,所以少了1个字符:)
Moris Zucca 2014年

哇-这是APL擅长的挑战。
isaacg 2014年

12

Python 2,115字节

def T(m):o=[];exec'm=zip(*m)[::-1]\nfor r in m[::-1]:\n n=k=0\n for x in r:k+=x>n;n=max(x,n)\n o+=[k]\n'*4;return o

那里有很多列表翻转。

将输入作为嵌套列表(例如,使用调用T([[4,3,5,2,1],[5,4,1,3,2],[1,5,2,4,3],[2,1,3,5,4],[3,2,4,1,5]]))。输出是单个平面列表。

取消高尔夫:

def T(m):
 o=[]
 for _ in [0]*4:
  m=zip(*m)[::-1]
  for r in m[::-1]:
   n=k=0
   for x in r:k+=x>n;n=max(x,n)
   o+=[k]
 return o

备选方案115:

def T(m):o=[];exec'm=zip(*m)[::-1];o+=[len(set([max(r[:i+1])for i in range(len(r))]))for r in m[::-1]];'*4;return o

我不知道为什么这可以与列表理解一起使用,但是可以NameError与集合理解一起使用...

太长了一点,但是如果有人感兴趣的话,是的,可以将其简化为lambda!

T=lambda m:[len({max(r[:i+1])for i in range(len(r))})for k in[1,2,3,4]for r in eval("zip(*"*k+"m"+")[::-1]"*k)[::-1]]

Pyth,25个字节

V4=Q_CQ~Yml{meS<dhkUd_Q)Y

必需的Pyth端口。

通过STDIN输入列表,例如[[4, 3, 5, 2, 1], [5, 4, 1, 3, 2], [1, 5, 2, 4, 3], [2, 1, 3, 5, 4], [3, 2, 4, 1, 5]]

在线尝试 ...就是我要说的,但是不幸的是,出于安全原因,在线解释器不允许在嵌套括号中使用eval。请改用变通方法代码JcQ5V4=J_CJ~Yml{meS<dhkUd_J)Y,并输入一个扁平化列表,如[4, 3, 5, 2, 1, 5, 4, 1, 3, 2, 1, 5, 2, 4, 3, 2, 1, 3, 5, 4, 3, 2, 4, 1, 5]

(感谢@isaacg帮助高尔夫球了几个字节)


一对Pyth高尔夫球:<>是单侧切片算子,因此:d0hk可以转换为<dhkU在集合输入上是一样的Ul,因此Uld可以变成Ud
isaacg 2014年

@isaacg谢谢-似乎我的Pyth需要更新。我拥有的文档已过时。
Sp3000

11

CJam,29 27字节

q~{z_{[{1$e>}*]_&,}%pW%}4*;

输入像

[[4 3 5 2 1] [5 4 1 3 2] [1 5 2 4 3] [2 1 3 5 4] [3 2 4 1 5]]

输出像

[2 3 1 4 5]
[3 4 3 2 1]
[1 2 2 2 2]
[3 3 2 1 2]

怎么运行的

基本思想是使代码沿行工作,并逆时针旋转网格4次。为了计算塔数,我将每个塔提升到不产生“视觉差异”的程度(即,如果可见则不要更改它,或将其拉到塔前的相同高度)。它),然后我计算出不同的高度。

q~                          "Read and evaluate the input.";
  {                    }4*  "Four times...";
   z                        "Transpose the grid.";
    _                       "Duplicate.";
     {            }%        "Map this block onto each row.";
      [       ]             "Collect into an array.";
       {    }*              "Fold this block onto the row.";
        1$                  "Copy the second-to-topmost element.":
          e>                "Take the maximum of the top two stack elements.";
                            "This fold replaces each element in the row by the
                             maximum of the numbers up to that element. So e.g.
                             [2 1 3 5 4] becomes [2 2 3 5 5].";
               _&,          "Count unique elements. This is how many towers you see.";
                    p       "Print array of results.";
                     W%     "Reverse the rows for the next run. Together with the transpose at
                             the start this rotates the grid counter-clockwise.";
                          ; "Get rid of the grid so that it isn't printed at the end.";


5

J,35个字符

(+/@((>./={:)\)"2@(|.@|:^:(<4)@|:))

例:

   t=.4 3 5 2 1,. 5 4 1 3 2,. 1 5 2 4 3,. 2 1 3 5 4,. 3 2 4 1 5
   (+/@((>./={:)\)"2@(|.@|:^:(<4)@|:)) t
2 3 1 4 5
3 4 3 2 1
1 2 2 2 2
3 3 2 1 2

在这里尝试。


5

哈斯克尔(113)

import Data.List
f(x:s)=1+f[r|r<-s,r>x]
f _=0
r=reverse
t=transpose
(?)=map
l s=[f?t s,(f.r)?s,r$(f.r)?t s,r$f?s]

4

Mathematica,230,120,116,113 110字节

f=(t=Table;a=#;s=Length@a;t[v=t[c=m=0;t[h=a[[y,x]];If[h>m,c++;m=h],{y,s}];c,{x,s}];a=Thread@Reverse@a;v,{4}])&

用法:

f[{
  {4, 3, 5, 2, 1},
  {5, 4, 1, 3, 2},
  {1, 5, 2, 4, 3},
  {2, 1, 3, 5, 4},
  {3, 2, 4, 1, 5}
}]

{{2, 3, 1, 4, 5}, {3, 4, 3, 2, 1}, {1, 2, 2, 2, 2}, {3, 3, 2, 1, 2}}

a[[y]][[x]]a[[y,x]]。并且使用Array可能比短Table
Martin Ender 2014年

4

JavaScript, 335 264 256 213

T=I=>((n,O)=>(S=i=>i--&&O.push([])+S(i)+(R=(j,a,x)=>j--&&R(j,0,0)+(C=k=>k--&&((!(a>>(b=I[(F=[f=>n-k-1,f=>j,f=>k,f=>n-j-1])[i]()][F[i+1&3]()])))&&++x+(a=1<<b))+C(k))(n)+O[i].push(x))(n,0,0))(4)&&O)(I.length,[],[])

在浏览器的JavaScript控制台中进行评估(我使用的是Firefox 34.0,在Chrome 39中似乎不起作用??)

JSON.stringify(T([[4, 3, 5, 2, 1], [5, 4, 1, 3, 2], [1, 5, 2, 4, 3], [2, 1, 3, 5, 4], [3, 2, 4, 1, 5]]));

这是当前未实现代码的化身-越来越难以理解:

function countVisibleTowers(input) {
  return ((n, out) =>
      (sideRecurse = i =>
          i-- &&
          out.push([]) +
          sideRecurse(i) +
          (rowRecurse = (j, a, x) =>
              j-- &&
              rowRecurse(j, 0, 0) +
              (columnRecurse = k =>
                  k-- &&
                  ((!(a >> (b = input[
                                        (offsetFtn = [
                                            f => n - k - 1,   // col negative
                                            f => j,           // row positive
                                            f => k,           // col positive
                                            f => n - j - 1    // row negative
                                        ])[i]()
                                     ]
                                     [
                                        offsetFtn[i + 1 & 3]()
                                     ]))) &&
                  ++x +
                  (a = 1 << b)) +
                  columnRecurse(k)
              )(n) +
              out[i].push(x)
          )(n, 0, 0)
      )(4) && out
  )(input.length, [], [])
}

我故意没有看其他任何答案,而是想看看自己是否可以解决问题。我的方法是将输入数组展平为一维数组,并预先计算从所有四个方向到行的偏移量。然后我使用右移来测试下一个塔是否虚假,如果是,则为每行增加计数器。

我希望有很多方法可以改善这一点,也许不是预先计算偏移量,而是在1D输入数组上使用某种溢出/取模方法?也许结合我的循环,获得更多功能,重复数据删除。

任何建议,将不胜感激!

更新#1:进步,我们拥有技术!我能够摆脱预先计算出的偏移量,并将它们与三元运算符串在一起进行内联。也能够摆脱我的if语句并将for循环转换为whiles。

更新2:这非常令人沮丧;我没有披萨派对。我认为使用功能和使用递归将节省很多字节,但是最初的几次尝试最终最多增加了100个字符!无奈之下,我全力以赴地使用ES6粗箭头功能来减少它。然后我开始用算术运算符替换布尔运算符,并在可能的情况下删除括号,分号和空格。我什至退出声明我的变量,并用本地符号污染了全局名称空间。脏,脏。经过所有这些努力,我以高达8个字符的优势击败了我的Update#1得分,降至256个。

如果我对Update#1功能应用相同的无情优化和ES6技巧,那么我将比这个成绩高出一英里。我可能会执行一次Update#3,以查看其外观。

更新#3:事实证明,胖箭头递归方法具有更多的生命,我只需要直接使用二维输入即可,而不是将其展平,从而更好地利用闭合作用域。我重写了两次内部数组偏移量计算,并获得了相同的分数,因此这种方法可能会被淘汰!


3

Java 352 350 325个字节...

class S{public static void main(String[]a){int n=a.length,i=0,j,k,b,c;int[][]d=new int[n][n];for(;i<n;i++)for(j=0;j<n;)d[i][j]=a[i].charAt(j++);for(i=0;i<4;i++){int[][]e=new int[n][n];for(k=0;k<n;k++)for(j=0;j<n;)e[n-j-1][k]=d[k][j++];d=e;for(j=n;j-->(k=c=b=0);System.out.print(c))for(;k<n;k++)b=d[j][k]>b?d[j][k]+0*c++:b;}}}

输入像 43521 54132 15243 21354 32415

输出像: 23145343211222233212

缩进:

class S{
    public static void main(String[]a){
        int n=a.length,i=0,j,k,b,c;
        int[][]d=new int[n][n];
        for(;i<n;i++)
            for(j=0;j<n;)d[i][j]=a[i].charAt(j++);
        for(i=0;i<4;i++){
            int[][]e=new int[n][n];
            for(k=0;k<n;k++)
                for(j=0;j<n;)e[n-j-1][k]=d[k][j++];
            d=e;
            for(j=n;j-->(k=c=b=0);System.out.print(c))
                for(;k<n;k++)b=d[j][k]>b?d[j][k]+0*c++:b;
        }
    }
}

任何提示将非常感谢!


您在for循环之间有一些额外的空格
骄傲的haskeller 2014年

@proud haskeller谢谢!
TheNumberOne 2014年

您可以更改for(;i<n;i++)for(;++i<n;)并初始化i-1。然后用这些做东西。您也可以对另一个循环执行相同的操作。
骄傲的haskeller 2014年

您可以使用a[i].charAt(j)-'0'而不是显式解析。这也不需要输入中的定界符(使输入格式更像输出格式)。
anatolyg 2014年

另外,在for-loops中,您总是可以将有用的内容填充到“ loop增量”部分中。这使代码更加晦涩,并删除了一个分号。例如:for(j=n;j-->0;System.out.print(c))
anatolyg 2014年

1

Python 2-204字节

def f(l):n=len(l);k=[l[c]for c in range(n)if l[c]>([0]+list(l))[c]];return f(k)if k!=l else n
r=lambda m:(l[::-1]for l in m)
m=input();z=zip(*m);n=0
for t in z,r(m),r(z),m:print map(f,t)[::1-(n>1)*2];n+=1

这可能是一个非常糟糕的高尔夫。我认为这个问题很有趣,因此我决定在不考虑其他任何人的解决方案的情况下解决它。当我输入这句话时,我还没有看这个问题的答案。如果其他人已经完成了较短的Python程序,我不会感到惊讶;)

I / O示例

$ ./towers.py <<< '[[4,3,5,2,1],[5,4,1,3,2],[1,5,2,4,3],[2,1,3,5,4],[3,2,4,1,5]]'
[2, 3, 1, 4, 5]
[3, 4, 3, 2, 1]
[1, 2, 2, 2, 2]
[3, 3, 2, 1, 2]

您可以选择在输入中包含空格。老实说,几乎在任何地方。只要您能eval(),它就会起作用。

说明

该程序唯一有趣的部分是第一行。它定义了一个函数f(l),该函数告诉您连续可以看到多少个塔,程序的其余部分只是将该函数应用于每个可能的位置。

调用时,它将找到的长度l并将其保存在变量中n。然后,它k使用这种非常怪异的列表理解来创建一个新变量:

[l[c]for c in range(n)if l[c]>([0]+list(l))[c]]

分解时还算不错。从此n==len(l)if正义面前的一切就代表了l。但是,使用if我们可以从列表中删除一些元素。我们构造一个列表([0]+list(l)),这仅仅是“ l0添加到开始”(忽略呼叫list(),这是唯一的存在,因为有时l是一台发电机,我们需要确保它实际上是这里的列表)。l[c]如果大于,则仅列入最终列表([0]+list(l))[c]。这有两件事:

  • 由于列表的开头有一个新元素,因此每个元素的索引l[c]变为c+1。我们正在有效地将每个元素与其左侧的元素进行比较。如果更大,则可见。否则,它将被隐藏并从列表中删除。
  • 第一塔总是可见的,因为没有什么可以阻挡它。因为我们将0放在开头,所以第一个塔总是更大。(如果我们不这样做[0]+废话,只是相比l[c]l[c-1],巨蟒将第一塔指数比较最后一个(你可以到一个列表从最终用-1-2等),因此,如果最后的塔比更高首先,我们会得到错误的结果。

说完所有内容后,它l包含一些塔,并且k包含不短于其左邻的塔。如果都不是(例如f([1,2,3,4,5])),则l == k。我们知道没有什么要做和返回的n(列表的长度)。如果为l != k,则表示这一次至少拆除了一个塔,可能还有更多工作要做。因此,我们返回f(k)。天哪,我喜欢递归。有趣的是,f总是比严格的“必需”要深一层。当生成将要返回的列表时,该函数起初没有办法知道。

当我开始编写此解释时,该程序的长度为223个字节。在解释事情时,我意识到有保存字符的方法,所以很高兴我输入了这个信息!最大的例子是,f(l)它最初是作为无限循环实现的,在我意识到递归将起作用之前,它是在计算完成时打破的。它只是表明,您想到的第一个解决方案并不总是最好的。:)


0

Matlab,(123)(119)

function r=m(h);p=[h rot90(h) rot90(h,2) rot90(h,3)];for i=2:size(p) p(i,:)=max(p(i,:),p(i-1,:));end;r=sum(diff(p)>0)+1

像这样使用:

m([
 4     3     5     2     1;
 5     4     1     3     2;
 1     5     2     4     3;
 2     1     3     5     4;
 3     2     4     1     5])

 [2 3 1 4 5 3 4 3 2 1 1 2 2 2 2 3 3 2 1 2]

C#,降至354 ...

与TheBestOne使用的方法不同。

using System;
using System.Linq;

class A
{
    static void Main(string[] h)
    {
        int m = (int)Math.Sqrt(h[0].Length),k=0;
        var x = h[0].Select(c => c - 48);
        var s = Enumerable.Range(0, m);
        for (; k < 4; k++)
        {
            (k%2 == 0 ? s : s.Reverse())
                .Select(j =>
                        (k > 0 && k < 3 ? x.Reverse() : x).Where((c, i) => (k % 2 == 0 ? i % m : i / m) == j)
                                                          .Aggregate(0, (p, c) =>
                                                                        c > p%10
                                                                            ? c + 10 + p/10*10
                                                                            : p, c => c/10))
                .ToList()
                .ForEach(Console.Write);
        }
    }
}

看来您是计算机粘贴\n而不是换行符,我只是将它们替换为空格,因此当有人进行复制时,代码会立即运行。我让自己删除最后一个end(即关闭功能,这是没有必要的),从而节省了额外的4个字,我希望那是OK =)
flawr

似乎matlab对空格不满意,因此我将其更改为分号。关于尾随的好点end,thx :)
zabalajka 2014年
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.