하스켈 , 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
합니다. 여기서 우리는 행에 정수 인덱스와 열에 홀수 정수 인덱스가있는 2 차원 배열을 압축합니다. 우리는 (i,j)
공식을 사용하여 정수 쌍으로부터 고유 한 정수를 만들 수 있기 때문에 이렇게 합니다 (2^i)*(2j+1)
. 에 대해 홀수 정수만 생성하면 3 바이트를 절약 j
하면서을 계산하는 것을 건너 뛸 수 있습니다 2*j+1
.
고유 번호를 사용하면 이제 행렬의 값을 기반으로 부호 만 곱하면됩니다. 2*x-1
되풀이
반복은 다음과 같이 수행됩니다.
(until=<<((==)=<<))((.)>>=id$transpose.map l)
입력은리스트리스트의 형태이기 때문에, 우리는 각 행에서 이웃 비교를 수행하고, 행렬을 전치하고, 각 행에서 다시 비교를 수행합니다 (조치로 인해 이전의 열이었던 것입니다). 이 단계 중 하나를 수행하는 코드는
((.)>>=id$transpose.map l)
여기서 l
비교 기능 (아래에 자세히 설명되어 있음) transpose.map l
은 비교 및 조옮김 단계의 절반을 수행합니다. 이 경우, 연산자 우선 순위 규칙으로 인해 (.)>>=id
포인트없는 형태이며 \f -> f.f
1 바이트 더 짧은 인수를 두 번 수행합니다 .
l
위의 행에서으로 정의됩니다 l x=z(!)(z(!)x(0:x))$tail x++[0]
. 이 코드 (!)
는 목록 x
을 오른쪽으로 이동 한 목록 0:x
과 왼쪽으로 이동 한 목록 tail x++[0]
으로 차례로 압축하여 모든 셀에 대해 비교 연산자 (아래 참조)를 수행합니다 . 사전 처리 된 행렬에서는 절대로 이동할 수 없으므로 이동 된 목록을 채우는 데 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
0보다 항상 더 큰 우리가 가진 최대 격차로 선택할 수 있도록, a
다시 얻을 a
. 그렇지 않으면 max(a*a)(a*b)
is abs(a)*max(abs(a),(abs(b))
이고 이것을로 나눔으로써 절대 값이 더 큰 숫자 인을 a
얻습니다 sgn(a)*max(abs(a),abs(b))
.
((.)>>=id$transpose.map l)
고정 점에 도달 할 때까지 함수를 반복하기 위해이 stackoverflow answer(until=<<((==)=<<))
에서 가져온을 사용 합니다 .
후 처리
후 처리를 위해 부품을 사용합니다
(\x->length.($x).filter<$>[(>0),(<0)]).nub.(>>=id)
단계의 모음 일뿐입니다.
(>>=id)
리스트리스트를 단일리스트로 스쿼시하고,
nub
복식을 제거
(\x->length.($x).filter<$>[(>0),(<0)])
하고,리스트를 한 쌍의리스트로 분할하고 (양을위한 것, 음을위한 것), 길이를 계산합니다.
[[1,0];[0,1]]
대각선 연결이 포함되지 않도록 테스트 케이스를 추가해야합니다