Проблема "Заповнити сітку"


36

Завдання з простими правилами, але нетривіальними алгоритмами. :-)

Завдання

Візьміть дані у вигляді цілих чисел, розділених пробілом:

N A B S

Де N - бічна довжина 2D квадратної матриці, заповненої унікальними числами (цілими числами) між A і B включно. Для кожного рядка та стовпця в цій матриці сума завжди однакова: S. (Іншими словами, матриця - це напівмагічний квадрат).

Примітка:

Усі цифри позитивні. Виняток становить A, який може бути 0.

Приклади

Для

3 1 10000 2015

правильним рішенням було б

введіть тут опис зображення

Для

8 1 300 500

правильним рішенням було б

введіть тут опис зображення

Вихідні дані

Вихід повинен бути таблицею ASCII. Приклад першого прикладу вище:

 384  159 1472
1174  499  342
 457 1357  201

Цілі вирівнювання, задані пробілами. Ширина кожного стовпця - це ширина найбільшого цілого числа в цьому стовпці.

Оцінка балів

Це , тому найкоротший код у байтах виграє. Застосовуються стандартні лазівки (особливо про вбудовані для вирішення цієї проблеми). Вам не потрібно піклуватися про неправильні або інакше неможливі введення даних (включаючи від’ємні цифри). Будь ласка, надайте зразок результату у своїй відповіді (обов’язково) для другого прикладу вище.


1
Чи дозволяється нам генерувати випадкові числа між A і B, поки вони не підсумовують правильно і не є унікальними?
lirtosiast

Просто щоб перевірити, A, Bі Nможе бути негативним?
xnor

2
minxomat, я не кажу, що це найкраще рішення, яке я можу придумати, я кажу, що це може бути найкоротше.
lirtosiast

3
@LuisMendo Ви повинні генерувати вибірковий вибір відповідно до завдання. Якщо ти зможеш цим керувати протягом життя за допомогою грубого підходу, я буду вражений. :-). Я міг би це виключити, але це було б занадто нечітко, оскільки найпопулярніше рішення (а саме GA) все ще включає випадковість. Також я не хочу змінювати правила, коли хтось уже може працювати над рішенням.
mınxomaτ

1
@minxomat Усі три ваші аргументи - це дуже хороші моменти :-)
Луїс Мендо

Відповіді:


19

CJam, 119 91 байт

q~:M;),>:R;(:L{{R{ML)d/-Y#)mr}$L/L<2{{M1$:+-+}%z}*:U:+__O|=R*-}gU{:s_:,:e>f{Se[}}%zSf*N*}M?

Це вірно правильний, недетермінований підхід.

На моєму робочому столі другий тестовий випадок закінчується менш ніж за 10 хвилин.

Перший випадок закінчується миттєво. Спробуйте його в Інтернеті в інтерпретаторі CJam .

Вибірка зразка

$ cjam grid.cjam <<< '8 1 300 500'
77  66  37 47  56  46 86  85
63 102  70 72  49  54 81   9
62  69  58 57  71  17 48 118
64  65  67 87  53  44 80  40
73  60  55 89  51  76 84  12
68  59  28 78  74  38 50 105
61  75  52 43 125  83 42  19
32   4 133 27  21 142 29 112

Ідея

Без обмежень за часом ми можемо просто випадковим чином генерувати квадрати, поки не знайдемо дійсний квадрат. Цей підхід ґрунтується на цій ідеї, додаючи дві оптимізації:

  • Замість того, щоб псевдовипадково генерувати квадрат бічної довжини N , ми генеруємо квадрати бічної довжини N-1 , додаємо один стовпець, щоб утворити прямокутник N × (N-1) , рядки якого мають суму S , а потім один рядок утворюють квадрат довжина сторони Н , стовпці якої є сума S .

    Так як сума елементів всіх стовпців буде NS і сума елементів перших N-1 рядків (N-1) S , останній рядок буде також мати суму S .

    Однак цей процес може створити недійсну матрицю, оскільки немає гарантії, що всі елементи останнього рядка та стовпця будуть унікальними або потраплятимуть у діапазон [A ... B] .

  • Вибір квадрата унікальних цілих чисел у [A ... B] та довжини сторони N-1 рівномірно навмання може зайняти занадто довго. Ми якось повинні розставити пріоритети квадратів, які мають більший шанс отримати результат дійсного квадрата бічної довжини N після застосування процесу, детально описаного в попередній точці кулі.

    Беручи під увагу , що кожен рядок і стовпець повинен мати суму S , його елементи мають в середньому S / N . Таким чином, вибір більшої кількості елементів, близьких до середнього, повинен збільшити наші шанси.

    Для кожного I в [A ... B] псевдовипадково вибираємо поплавок між 0 і (I - S / N) 2 + 1 і сортуємо елементи [A ... B] за вибраними плавцями. Ми зберігаємо перші N 2 числа і розміщуємо їх у порядку читання у квадраті.

    Якщо припустити ідеально рівномірний розподіл всіх дійсних чисел між 0 і (I - S / N) 2 + 1 на кожному кроці, всі квадрати мають ненульову ймовірність вибору, що означає, що процес закінчиться в підсумку.

Код

q~          e# Read all input from STDIN and evaluate it.
:M;         e# Save "S" in M and discard it from the stack.
),>:R;      e# Transform "A B" into [A ... B], save in R and discard.
(:L         e# Save "N - 1" in L and keep it on the stack.
{           e# If L is non-zero:
  {         e#   Do:
    R{      e#     For each I in R:
      ML)d/ e#       Compute M/Double(L+1).
      -Y#   e#       Subtract the result from I and square the difference.
      )mr   e#       Add 1 and pick a non-negative Double below the result.
    }$      e#     Sort the values of I according to the picks.
    L/      e#     Split the shuffled R into chunks of length L.
    L<      e#     Keep only the first L chunks.
    2{      e#     Do twice:
      {     e#       For each row of the  L x L array.
        M1$ e#       Push M and a copy of the row.
        :+- e#       Add the integers of the row and subtract their sum from M.
        +   e#       Append the difference to the row.
      }%    e#
      z     e#       Transpose rows and columns.
    }*      e#
    :U:+    e#     Save the result in U and concatenate its rows.
    __O|    e#     Push two copies. Deduplicate the second copy.
    =R*     e#     Push R if all elements are unique, an empty array otherwise.
    -       e#     Remove the result's elements from U's elements.
  }g        e#   If the resulting array is non-empty, repeat the loop.
  U{        e#   For each row in U:
    :s      e#     Convert its integers into strings.
    _:,     e#     Copy and replace each string with its length.
    :e>     e#     Compute the maximum length.
    f{      e#     For each integer, push the maximum length; then
      Se[   e#       Left-pad the integer with spaces to that length.
    }       e#
  }%        e#
  z         e#   Transpose rows with columns.
  Sf*N*     e#   Join columns by spaces, rows by linefeeds.
}M?         e# Else, push M.
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.