Haskell , 228 227 225 224 byte
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..]
Hãy thử trực tuyến!
Giải trình:
Ý tưởng cho giải pháp này như sau: Khởi tạo ma trận với các giá trị duy nhất trong mỗi ô, dương cho 1
và âm cho 0
. Sau đó liên tục so sánh từng ô với các ô lân cận và, nếu hàng xóm có cùng dấu nhưng một số có giá trị tuyệt đối lớn hơn, hãy thay thế số của ô bằng số của neighbour. Khi điểm này đạt một điểm cố định, hãy đếm số lượng số dương khác biệt cho số 1
vùng và số âm khác biệt cho số 0
vùng.
Trong mã:
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..]
có thể được tách thành tiền xử lý (gán số cho các ô), lặp và xử lý sau (đếm ô)
Sơ chế
Phần tiền xử lý là chức năng
z(\i->z(\j x->2^i*j*(2*x-1))[1,3..])[1..]
Mà sử dụng z
như viết tắt zipWith
để cạo một vài byte. Những gì chúng ta làm ở đây là nén mảng hai chiều với các chỉ số nguyên ở các hàng và các chỉ số nguyên lẻ ở các cột. Chúng tôi làm điều này vì chúng tôi có thể xây dựng một số nguyên duy nhất từ một cặp số nguyên(i,j)
bằng công thức (2^i)*(2j+1)
. Nếu chúng ta chỉ tạo các số nguyên lẻ cho j
, chúng ta có thể bỏ qua việc tính toán 2*j+1
, tiết kiệm ba byte.
Với số duy nhất, giờ đây chúng ta chỉ phải nhân một dấu dựa trên giá trị trong ma trận, được lấy là 2*x-1
Lặp lại
Lặp lại được thực hiện bởi
(until=<<((==)=<<))((.)>>=id$transpose.map l)
Do đầu vào ở dạng danh sách các danh sách, chúng tôi thực hiện so sánh hàng xóm trên mỗi hàng, hoán đổi ma trận, thực hiện so sánh trên mỗi hàng một lần nữa (do chuyển vị là các cột trước đó) và hoán vị lại. Mã thực hiện một trong các bước này là
((.)>>=id$transpose.map l)
trong đó l
chức năng so sánh (chi tiết bên dưới) và transpose.map l
thực hiện một nửa các bước so sánh và chuyển vị. (.)>>=id
thực hiện đối số của nó hai lần, là dạng không có điểm \f -> f.f
và ngắn hơn một byte trong trường hợp này do các quy tắc ưu tiên toán tử.
l
được định nghĩa trong hàng trên như l x=z(!)(z(!)x(0:x))$tail x++[0]
. Mã này thực hiện một toán tử so sánh (!)
(xem bên dưới) trên mỗi ô với hàng xóm bên trái đầu tiên và sau đó với hàng xóm bên phải của nó, bằng cách nén danh sách x
với danh sách dịch chuyển bên phải 0:x
và danh sách dịch chuyển tráitail x++[0]
lần lượt. Chúng tôi sử dụng các số 0 để đệm các danh sách đã thay đổi, vì chúng không bao giờ có thể xảy ra trong ma trận được xử lý trước.
a!b
được định nghĩa trong hàng trên này như a!b=div(max(a*a)(a*b))a
. Những gì chúng tôi muốn làm ở đây là phân biệt trường hợp sau đây:
- Nếu
sgn(a) = -sgn(b)
, chúng ta có hai khu vực đối lập trong ma trận và không muốn thống nhất chúng, vì vậy a
vẫn không thay đổi
- Nếu
sgn(b) = 0
, chúng ta có trường hợp góc b
là phần đệm và do đó a
không thay đổi
- Nếu
sgn(a) = sgn(b)
, chúng tôi muốn thống nhất hai khu vực và lấy một khu vực có giá trị tuyệt đối lớn hơn (vì sự thuận tiện).
Lưu ý rằng sgn(a)
không bao giờ có thể được 0
. Chúng tôi thực hiện điều này với công thức được đưa ra. Nếu các dấu hiệu của a
và b
khác nhau, a*b
nhỏ hơn hoặc bằng 0, trong khi a*a
luôn lớn hơn 0, vì vậy chúng tôi chọn nó là mức tối đa và chia a
cho để lấy lại a
. Nếu không, max(a*a)(a*b)
là abs(a)*max(abs(a),(abs(b))
, và bằng cách chia này bằng cách a
, chúng tôi nhận sgn(a)*max(abs(a),abs(b))
, đó là số có giá trị tuyệt đối lớn hơn.
Để lặp lại hàm ((.)>>=id$transpose.map l)
cho đến khi nó đạt đến một điểm cố định, chúng tôi sử dụng (until=<<((==)=<<))
, được lấy từ câu trả lời stackoverflow này .
Hậu xử lý
Để xử lý hậu kỳ, chúng tôi sử dụng phần
(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id)
mà chỉ là một tập hợp các bước.
(>>=id)
xóa danh sách các danh sách thành một danh sách,
nub
loại bỏ gấp đôi,
(\x->length.($x).filter<$>[(>0),(<0)])
phân chia danh sách thành một cặp danh sách, một cho danh sách dương và một cho số âm và tính độ dài của chúng.
[[1,0];[0,1]]
để đảm bảo không bao gồm kết nối đường chéo