Скільки башт можна побачити?


29

Це питання ґрунтується на головоломці "Вежі-розміщення чисел" (також відомі як "Хмарочоси"), в яку можна грати в Інтернеті . Ваша мета - прийняти рішення головоломки та визначити підказки - кількість башт, видимих ​​уздовж кожного ряду та стовпця. Це кодовий гольф, тому виграє найменше байтів.

Як працює Вежа

Рішення головоломки 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

Наприклад, давайте подивимось на перший ряд.

 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

АПЛ 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 ви праві, дякую! Я також застосував ∪ / так на 1 char менше :)
Моріс Цука

Нічого собі - це такий виклик, на який вирішується APL.
isaacg

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відповідає наборі розуміння ...

Трохи задовго, але якщо когось цікавить - так, можна це звести до лямбда!

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їх можна перетворити <dhk. Uдля колекційних входів те саме Ul, що Uldможе бути перетворено на Ud.
isaacg

@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.";




4

Математика, 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.
Мартін Ендер

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 жиру, щоб справді її збити. Тоді я взявся замінити булеві оператори на арифметичні та видалити пароні, напівколонки та пробіли, куди тільки міг. Я навіть кинув оголошувати свої проблеми та забруднив глобальний простір імен своїми локальними символами. Брудне, брудне. Після всіх цих зусиль я переміг свій показник Оновлення №1 колосальними 8 символами, аж до 256. Blargh!

Якби я застосував ті самі нещадні оптимізації та трюки 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

@proud haskeller Дякую!
TheNumberOne

Ви можете змінити , for(;i<n;i++)щоб for(;++i<n;)і форматувати iв -1. Потім використовуйте їх, щоб робити речі. Те ж саме можна зробити і з іншою петлею.
гордий haskeller

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

Крім того, в for-loops, ви завжди можете вкласти щось корисне в частину "збільшення циклу". Це робить код більш незрозумілим та видаляє одну крапку з комою. Наприклад: for(j=n;j-->0;System.out.print(c)).
anatolyg

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

Здається, що матлаб не був задоволений пробілами, тому я змінив їх на крапки з комою. Хороший момент про трейлінг endхоч, thx :)
zabalajka
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.