Haskell , 228 227 225 224 bayt
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..]
Çevrimiçi deneyin!
Açıklama:
Bu çözüm için fikir aşağıdaki gibidir: Her hücrede benzersiz değerlere sahip matrisi, pozitif 1ve negatif için başlat 0. Daha sonra her bir hücreyi tekrar komşularıyla karşılaştırın ve eğer komşu aynı işarete ancak daha büyük bir mutlak değere sahip bir sayıya sahipse, hücrenin numarasını komşunun numarasıyla değiştirin. Bu, sabit bir noktaya ulaştığında, bölge sayısı için belirgin pozitif sayıları ve sayı 1için belirgin negatif sayıları sayın .0 .
Kodunda:
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..]
ön işleme (hücrelere sayı atama), yineleme ve son işleme (hücreleri sayma) ayrılabilir
Ön İşleme
Ön işleme bölümü fonksiyondur
z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
Birkaç byte'ı tıraş etmek ziçin kısaltma olarak kullanılır zipWith. Burada yaptığımız şey, iki boyutlu diziyi satırlarda tamsayı indeksleri ve sütunlarda tek tamsayı dizinleri ile sıkıştırmak. Bunu (i,j), formülü kullanarak bir çift tam sayıdan benzersiz bir tam sayı oluşturabileceğimiz için yapıyoruz (2^i)*(2j+1). Eğer için sadece tuhaf tamsayılar üretersek , üç bayt tasarrufu jyaparak hesaplamayı geçebiliriz 2*j+1.
Eşsiz sayı ile, şimdi sadece matristeki değere dayalı bir işaretle çarpmak zorundayız. 2*x-1
tekrarlama
Yineleme tarafından yapılır
(until=<<((==)=<<))((.)>>=id$transpose.map l)
Girdi bir liste listesi biçiminde olduğundan, her satıra komşu karşılaştırması yaparız, matrisi çeviririz, her satırda karşılaştırmayı tekrar yaparız (translasyon nedeniyle daha önce sütunların ne olduğudır) ve tekrar dönüştürür. Bu adımlardan birini gerçekleştiren kod şudur:
((.)>>=id$transpose.map l)
lKarşılaştırma fonksiyonu nerede (aşağıda detaylandırılmıştır) ve transpose.map lkarşılaştırma ve aktarma adımlarının yarısını gerçekleştirir. (.)>>=idArgümanını iki kez gerçekleştirir, \f -> f.fbu durumda operatör öncelik kuralları nedeniyle , amaçsız ve bir bayt daha kısadır.
lyukarıdaki satırda tanımlanmıştır l x=z(!)(z(!)x(0:x))$tail x++[0]. Bu kod (!), listeyi xsağa kaydırılan liste 0:xve sola kaydırılan liste tail x++[0]sırayla sıkıştırmak suretiyle, önce sol komşusu olan ve ardından sağ komşusu olan her hücrede bir karşılaştırma operatörü (aşağıya bakınız) gerçekleştirir . Önceden işlenmiş matriste asla bulunamadıkları için kaydırılmış listeleri doldurmak için sıfırları kullanırız.
a!bBunun üstündeki satırda tanımlanmıştır a!b=div(max(a*a)(a*b))a. Burada yapmak istediğimiz, aşağıdaki durum ayrımıdır:
- Eğer
sgn(a) = -sgn(b)matristeki iki zıt alanımız varsa ve onları birleştirmek istemiyorsak, o zaman adeğişmeden kalır.
- Öyleyse
sgn(b) = 0, byastığın olduğu ve bu nedenle adeğişmeden kalan köşe kılıfına sahibiz.
- Eğer
sgn(a) = sgn(b)bu iki alanı birleştirmek ve mutlak değeri en büyük olanı almak istiyoruz (kolaylık uğruna).
Not sgn(a)olamaz 0. Bunu, verilen formülle başardık. Belirtileri varsa ave bfarklılık a*bise, az ya da sıfır eşit a*asıfırdan her zaman büyüktür biz maksimum ve böl olarak almak, böylece ageri almak için a. Aksi takdirde, max(a*a)(a*b)bir abs(a)*max(abs(a),(abs(b))ve bu bölerek a, bundan elde sgn(a)*max(abs(a),abs(b))büyük bir mutlak değere sahip numarası olan.
Fonksiyonu ((.)>>=id$transpose.map l)sabit bir noktaya gelinceye kadar yinelemek için (until=<<((==)=<<)), bu stackoverflow yanıtından alınan kullanın .
Rötuş
Postprocessing için bu kısmı kullanıyoruz
(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id)
Bu sadece bir adımlar topluluğudur.
(>>=id)listeler listesini tek bir listeye yerleştirir,
nubçiftlerden kurtulur
(\x->length.($x).filter<$>[(>0),(<0)]), listeyi bir çift listeye ayırır, biri pozitif, diğeri negatif sayılar için hesaplar ve uzunluklarını hesaplar.
[[1,0];[0,1]]Çapraz bağlantının dahil olmadığından emin olmak gibi bir