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]]