Haskell , 228 227 225 224 байт
import Data.List
z=zipWith
a!b=div(max(a*a)(a*b))a
l x=z(!)(z(!)x(0:x))$tail x++[0]
s=(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id).(until=<<((==)=<<))((.)>>=id$transpose.map l).z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
Спробуйте в Інтернеті!
Пояснення:
Ідея цього рішення полягає в наступному: ініціалізуйте матрицю з унікальними значеннями в кожній комірці, позитивними для 1
та негативними для 0
. Потім кілька разів порівнюйте кожну клітинку з сусідами і, якщо сусід має той самий знак, але число з більшим абсолютним значенням, замініть номер комірки на номер сусіда. Як тільки це досягне фіксованої точки, підрахуйте кількість чітких додатних чисел для кількості 1
регіонів та виразних від’ємних чисел для кількості0
регіонів.
У коді:
s=(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id).(until=<<((==)=<<))((.)>>=id$transpose.map l).z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
можна розділити на попередню обробку (присвоєння числа осередкам), ітерацію та післяобробку (підрахунок комірок)
Попередня обробка
Попередня обробка - це функція
z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
Який використовується z
як абревіатура для zipWith
гоління кількох байт. Що ми робимо тут, це зафіксувати двовимірний масив з цілими індексами у рядках та непарними цілими індексами у стовпцях. Ми робимо це, оскільки можемо створити унікальне ціле число з пари цілих чисел, (i,j)
використовуючи формулу (2^i)*(2j+1)
. Якщо ми генеруємо лише непарні цілі числа j
, ми можемо пропустити обчислення 2*j+1
, зберігаючи три байти.
За допомогою унікального числа нам тепер залишається лише множитися на знак, виходячи зі значення в матриці, яке отримується як 2*x-1
Ітерація
Ітерація виконується
(until=<<((==)=<<))((.)>>=id$transpose.map l)
Оскільки введення у вигляді списку списків, ми виконуємо порівняння сусідів на кожному рядку, переносимо матрицю, проводимо порівняння на кожному рядку ще раз (що через транспозицію - це те, що було стовпцями раніше) і знову переміщуємо. Код, який виконує один із цих кроків, - це
((.)>>=id$transpose.map l)
де l
функція порівняння (детально описана нижче) і transpose.map l
виконує половину етапів порівняння та транспозиції. (.)>>=id
виконує свій аргумент двічі, будучи точковою формою \f -> f.f
та на один байт коротшою в цьому випадку завдяки правилам пріоритетності оператора.
l
визначається у рядку вище як l x=z(!)(z(!)x(0:x))$tail x++[0]
. Цей код виконує оператор порівняння (!)
(див. Нижче) для кожної комірки спочатку її лівим сусідом, а потім правою сусідкою, блискавками списку x
праворуч зміщеним списком 0:x
та лівим зміщеним спискомtail x++[0]
по черзі. Ми використовуємо нулі для прокладки зміщених списків, оскільки вони ніколи не можуть зустрічатися в попередньо обробленій матриці.
a!b
в рядку над цим визначається як a!b=div(max(a*a)(a*b))a
. Тут ми хочемо зробити наступне розрізнення:
- Якщо
sgn(a) = -sgn(b)
у матриці у нас є дві протилежні області, і ми не бажаємо їх уніфікувати, то це a
залишається незмінним
- Якщо у
sgn(b) = 0
нас є кутовий випадок, де b
прокладка і тому a
залишається незмінною
- Якщо
sgn(a) = sgn(b)
ми хочемо об'єднати дві області і взяти ту, що має більшу абсолютну величину (заради зручності).
Зауважте, цього sgn(a)
ніколи не може бути 0
. Ми виконуємо це за поданою формулою. Якщо ознаки a
і b
різняться, a*b
менше або дорівнює нулю, тоді a*a
як завжди більше нуля, тому ми вибираємо це як максимум і ділимось, a
щоб повернутися a
. В іншому випадку max(a*a)(a*b)
є abs(a)*max(abs(a),(abs(b))
, і ділимо це на a
, отримуємо sgn(a)*max(abs(a),abs(b))
, що є числом з більшим абсолютним значенням.
Для ітерації функції, ((.)>>=id$transpose.map l)
поки вона не досягла фіксованої точки, ми використовуємо (until=<<((==)=<<))
, що взято з цієї відповіді stackoverflow .
Подальша обробка
Для післяобробки ми використовуємо деталь
(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id)
що є лише сукупністю кроків.
(>>=id)
розбиває список списків на єдиний список,
nub
позбавляється від подвійних,
(\x->length.($x).filter<$>[(>0),(<0)])
розділяє список на пару списків, один на додатні та один на від’ємні числа, та обчислює їх довжину.
[[1,0];[0,1]]