Сколько башен вы видите?


29

Этот вопрос основан на головоломке «Башни с номерами» (также известной как «Небоскребы»), в которую можно играть онлайн . Ваша цель - найти решение головоломки и определить подсказки - количество башен, видимых вдоль каждого ряда и столбца. Это код гольф, поэтому побеждает меньше байтов.

Как работает Towers

Решением головоломки Towers является латинский квадрат - 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слева, потому что вы можете увидеть 4и 5. В 4преграждает 3из поля зрения и 5блокирует все остальное. Справа вы можете увидеть 3башни: 1, 2и 5.

Требования к программе

Напишите программу или функцию, которая принимает сетку чисел и выводит или печатает подсказки, двигаясь по часовой стрелке сверху слева.

вход

n*nLatin-квадрат с 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

Ответы:


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

@ngn, ты прав, спасибо! Я также применил ∪ / так на 1 символ меньше :)
Moris Zucca

Ух ты - это своего рода вызов APL.
Исаак

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]])). Выход представляет собой единый плоский список.

Ungolfed:

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с определенным пониманием ...

Слишком долго, но если кому-то интересно - да, это возможно до лямбды!

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 Golfs: <и >являются односторонними операторами срезов, так что :d0hkих можно превратить в <dhk. Uна коллекцию входов так же, как Ul, так что Uldможно превратить в Ud.
Исаак

@isaacg Спасибо - похоже, мой Пит нуждается в обновлении. Документ, который у меня есть, устарел.
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.";




4

Mathematica, 230 120 116 163 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.
Мартин Эндер,

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, [], [])
}

Я намеренно не смотрел ни на один из других ответов, я хотел посмотреть, смогу ли я что-нибудь решить сам. Мой подход состоял в том, чтобы сгладить входные массивы в одномерный массив и предварительно вычислить смещения строк со всех четырех направлений. Затем я использовал shift вправо, чтобы проверить, была ли следующая башня ложной, и если это так, то увеличить счетчик для каждого ряда.

Я надеюсь, что есть много способов улучшить это, возможно, не предварительно рассчитать смещения, а вместо этого использовать какое-то переполнение / модуль по входному массиву 1D? И, возможно, объединить мои циклы, получить более функциональный, дедуплицирующий.

Мы ценим любые предложения!

Обновление № 1 : прогресс, у нас есть технологии! Мне удалось избавиться от предварительно рассчитанных смещений и сделать их встроенными с помощью троичных операторов, соединенных вместе. Также удалось избавиться от моего оператора if и преобразовать циклы for в whiles.

Обновление № 2 : Это довольно неприятно; нет вечеринки с пиццей для меня. Я полагал, что функционирование и использование рекурсии уменьшат количество байтов, но мои первые несколько попыток закончились увеличением на целых 100 символов! В отчаянии я старался использовать функции жирных стрелок ES6, чтобы по-настоящему сократить его. Затем я занялся заменой логических операторов арифметическими и удалением паренов, точек с запятой и пробелов, где только мог. Я даже перестал объявлять свои переменные и загрязнил глобальное пространство имен своими локальными символами. Грязный, грязный. После всех этих усилий я побил свой результат в обновлении № 1 на целых 8 символов, до 256. Блин!

Если бы я применил те же безжалостные оптимизации и трюки ES6 к своей функции обновления №1, я бы побил этот показатель на милю. Я могу сделать обновление № 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

@ гордый haskeller Спасибо!
TheNumberOne

Вы можете изменить , for(;i<n;i++)чтобы for(;++i<n;)и инициализировать iв -1. Тогда используйте это, чтобы делать вещи. Вы можете сделать то же самое с другим циклом тоже.
гордый haskeller

Вы можете использовать a[i].charAt(j)-'0'вместо явного разбора. Это также не требует разделителей во входных данных (делает формат ввода более похожим на формат вывода).
Анатолий

Кроме того, в for-loops вы всегда можете вставить что-то полезное в часть «приращение цикла». Это делает код более неясным и удаляет одну точку с запятой. Например: for(j=n;j-->0;System.out.print(c)).
Анатолий

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;)

Пример ввода / вывода

$ ./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)), который просто « lс 0добавлением в начало» (игнорируйте вызов list(), это только там, потому что иногда lэто генератор, и мы должны убедиться, что это на самом деле список здесь). l[c]попадает в окончательный список, только если он больше, чем ([0]+list(l))[c]. Это делает две вещи:

  • Поскольку в начале списка есть новый элемент, индекс каждого l[c]становится c+1. Мы эффективно сравниваем каждый элемент с элементом слева от него. Если оно больше, это видно. В противном случае он будет скрыт и удален из списка.
  • Первая башня всегда видна, потому что ничто не может ее заблокировать. Поскольку мы ставим 0 в начале, первая башня всегда больше. (Если бы мы не делали эту [0]+чушь и просто по сравнению l[c]с l[c-1], Python бы сравнить первую башню до последнего (вы можете индекса в список с конца с -1, -2и т.д.), поэтому если последняя башня была выше , чем Во-первых, мы получили бы неправильный результат.

Когда все сказано и сделано, lсодержит некоторое количество башен и kсодержит каждую из тех, которая не короче своего непосредственного соседа слева. Если ни один из них не был (например, для f([1,2,3,4,5])), то l == k. Мы знаем, что ничего не осталось сделать и вернуть n(длина списка). Если l != kэто означает, что на этот раз была удалена хотя бы одна из башен, и, возможно, еще многое предстоит сделать. Итак, мы вернемся f(k). Боже, я люблю рекурсию. Интересно, что fвсегда повторяется на один уровень глубже, чем это строго «необходимо». Когда список, который будет возвращен, генерируется, функция не имеет возможности узнать это сначала.

Когда я начал писать это объяснение, длина этой программы составляла 223 байта. Объясняя вещи, я понял, что есть способы сохранить персонажей, поэтому я рад, что напечатал это! Самый большой пример - это то, что f(l)изначально он был реализован как бесконечный цикл, который был разорван во время вычислений, прежде чем я понял, что рекурсия сработает. Это просто говорит о том, что первое решение, о котором вы думаете, не всегда будет лучшим. :)


0

Матлаб, (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 символа, я надеюсь, что все было в порядке =)
flawr

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