나무를 센다


11

나무는 아무주기와 연결된, 무향 그래프이다. 당신의 임무는 주어진 수의 정점에 몇 개의 별개의 나무가 있는지 계산하는 것입니다.

두 나무가 동형 이 아닌 경우 별개의 것으로 간주됩니다 . 두 그래프는 각각의 정점이 쌍을 이룰 수있는 경우 다른 그래프의 정점과 짝을 이루는 정점 사이에 가장자리가있는 경우에만 한 그래프에 두 정점 사이에 가장자리가있는 방식으로 동형이됩니다. 더 자세한 설명은 위의 링크를 참조하십시오.

크기가 1에서 6까지 인 모든 다른 나무가 어떻게 보이는지 보려면 여기를보십시오 .

출력하려는 ​​시리즈 는 OEIS에서 A000055 입니다.

제한 사항 : 솔루션이 입력에서 실행 되려면 몇 분 이하의 시간이 소요 6됩니다. 이는 지수 시간 알고리즘을 제거하기위한 것이 아니라 모든 에지 세트에 대한 무차별 강제력과 같은 이중 지수 시간 알고리즘을 제거하기위한 것입니다.

입력 : 음이 아닌 정수

입력은 STDIN, 명령 행 매개 변수, 기능 입력 등을 포함한 모든 표준 수단에 의해 수행 될 수 있습니다.

출력 : 입력만큼 정점이 많은 고유 트리의 수입니다.

STDOUT, 함수 리턴 등을 포함한 모든 표준 수단으로 출력 할 수 있습니다.

예 : 0, 1, 2, 3, 4, 5, 6, 7 을 반환해야합니다 1, 1, 1, 1, 2, 3, 6, 11.

득점 : 코드 골프 (바이트). 가장 짧은 코드가 이길 수 있습니다!

표준 허점은 금지되어 있습니다.

답변:


3

CJam (69 바이트)

]qi:X,{1e|,:):N{N\f{1$%!*}W$.*:+}%1$W%.*:+N,/+}/W\+_1,*X=\_W%.*:+-Y/z

온라인 데모

설명

기본 아이디어는 OEIS에 설명 된 생성 기능을 구현하는 것입니다. 입력 은 불쾌한 특별한 경우이지만, 마지막으로 조정 한 결과 이 생성 되어 (절대 값의 경우)가 정리됩니다. 이것이 가장 이상한 트릭입니다.01z

.*:+를 세 번 반복하고로 추출하면 바이트를 절약 할 수있는 것처럼 보입니다 {.*:+}:F~. 그러나 이것은 외부 루프를 전혀 실행하지 않기 때문에 특별한 경우 중단됩니다 .0


항이 반복되는 A000081 의 보조 생성 기능을 사용합니다.

a[0] = 0
a[1] = 1
For n >= 1, a[n+1] = (sum_{k=1}^n a[n-k+1] * sum_{d|k} d * a[d]) / n

일부 언어에는 역 뫼비우스 변환 내장 된 언어가 있지만 CJam은 그렇지 않습니다. 내가 찾은 가장 좋은 방법은 배열 매핑 구축하는 것입니다 에 다음으로 점별 곱셈을 할 사용 . 편리 여기 참고 쌓아합니다 가중치를 설정할 때 우리가 0으로 피할 부문에 원하기 때문에, 인덱스 1부터 시작. 또한 포인트 단위 연산에 제공된 두 배열의 길이가 동일하지 않으면 더 긴 배열의 값은 그대로 유지됩니다. 따라서 우리는 의 첫 번째 항을 취 하거나 가중치 배열을 이동시켜야합니다dkd×a[d]dk % d == 0 ? d : 0a.*akan. 후자는 더 짧아 보입니다. 따라서이 역 뫼비우스 변환은N\f{1$%!*}W$.*:+

역모 비우스 변환의 결과를 호출하면 M이제

a[n+1]=1nk=1na[nk+1]×M[k]

분자는 분명히 컨볼 루션의 용어이므로 또는 의 사본을 뒤집은 다음 점별 곱셈과 합산을 통해 처리 할 수 ​​있습니다 . 다시, 우리의 인덱스는 에서 까지 다양 하며, 또한 에 하는 인덱스를 쌍으로 묶기를 원 하므로 0이 아닌 1에서 를 인덱스 것이 편리합니다. 이제 우리는 설명했습니다.aM1nn+1a

 qi:X,{   ,:):N{N\f{1$%!*}W$.*:+}%1$W%.*:+N,/+}/

보조 생성 기능의 포인트는 A000055의 공식 섹션에 의해 제공됩니다.

G.f.: A(x) = 1 + T(x) - T^2(x)/2 + T(x^2)/2,
where T(x) = x + x^2 + 2*x^3 + ... is the g.f. for A000081.

와 관련 , 우리가 찾는 출력은a

[x=0]+a[x]+12(a[x/2]i=0na[i]×a[ni])

여기서위한 홀수 우리 0. 얻을 I 그렇게 발견 한 최단의 방법은 제로 (함께 팽창한다 ), 그리고, x 번째의 요소를 가지고 ( ).a[x/2]x1,*X=

합계는 또 다른 컨볼 루션이지만 이번에는 0부터 색인을 작성하는 것이 편리합니다. 확실한 해결책은 0\+이지만 여기에는 약간의 최적화가 있습니다. 이후 , 회선의 두 조건이 보장 제로한다. 이것을 1부터 색인 할 수있는 기회로 삼을 수 있지만 특별한 경우 은 추악합니다. 대신 에 컨볼 루션을 사용하면 되며 빼기 및 나눈 후 항을 처리했습니다 합계 밖에서도.a[0]=0X=0W\+2a[x]+i=0na[i]×a[ni]2a[x]

그래서 우리는 설명했습니다

 qi:X,{   ,:):N{N\f{1$%!*}W$.*:+}%1$W%.*:+N,/+}/W\+_1,*X=\_W%.*:+-Y/

나머지 세부 사항은 특별한 경우와 관련이 있습니다. I 원래 함께 시작하여 더 엄격 재발 하였다 1]로부터 반복 로N=1

1]qi:X,1>{ ... }/

그 결과, 우리가 계산이다 으로 우리가 필요로하는 것보다 더 한 학기를 :. 인플레이션과 컨벌루션은 의 결과를 제공합니다 . (아마도 우리가 바라는 것보다 낫습니다. 우리가 이라는 용어에 대해 아무 것도하지 않았기 때문에 우리가 가져야 할 것 입니다.) 그래서 우리는 최종적으로 또는 표준 "대체"기술을 사용하여 세 개의 문자를 수정합니다 .X=0a[-1 1]0[x=0]X!+1e|

의 "오른쪽"길이 얻으려면 우리는 초기 공급 피할 필요가 로 메인 루프에서 생산하는 대신에, 그리고 . 완전히 간단한a1N=0

]qi:X,{ ... /+}/

분명히 0으로 나누기를 제공합니다. 그러나 우리가 시도하면

]qi:X,{1e| ... /+}/

그런 다음 작동합니다. 우리는 얻는다

             e# Stack: [] 0
1e|          e# Stack: [] 1
,:):N        e# Stack: [] [1]
{            e# We only execute this loop once
  N\f{1$%!*} e#   1 divides 1, so stack: [] [1]
  W$.*       e#   Remember: if the two arrays supplied to the pointwise operation
             e#   are not the same length then the values from the longer one are
             e#   left untouched. Stack: [] [1]
  :+         e#   Fold over a singleton. Stack: [] 1
}%           e# And that was a map, so stack: [] [1]
1$W%.*:+     e# Another [1] [] .*:+, giving the same result: 1
N,/          e# 1 / 1 = 1
+            e# And we append 1 to a giving [1]

필요한 값을 정확하게 생성합니다

이제 이면 주 루프가 실행되지 않으므로 맨 아래에 을 해킹 한 후 우리는를 얻습니다 . 우리는 컴퓨팅 끝내는데 , 이는 올바르지 않습니다. 그러나 수정하는 동안X=01[-1](112(1×1))=10111z


1

Pyth, 35 바이트

l{m`SmSSMcXdUQk2.pQusm+L,dhHGhHtQ]Y

데모.

이 프로그램은 두 부분으로 나눌 수 있습니다. 먼저 가능한 모든 트리를 생성 한 다음 중복을 제거합니다.

이 코드는 트리를 생성합니다 usm+L,dhHGhHtQ]Y. 나무는 다음과 같이 연결된 가장자리 목록으로 표시됩니다.

[0, 1, 0, 2, 2, 3, 1, 4]

각 숫자는 꼭짓점을 나타내며 두 ​​숫자는 모두 모서리입니다. 이미 존재하는 각 정점과 새로 작성된 정점 사이에 모서리를 반복적으로 추가하고 이전 단계에서 가능한 각 트리에 이것을 추가하여 빌드됩니다. 하나의 정점과 가장자리를 기존 트리에 반복적으로 추가하여 모든 트리를 생성 할 수 있기 때문에 가능한 모든 트리가 생성됩니다. 그러나 동형 나무가 생성됩니다.

다음으로, 각 트리마다 가능한 모든 레이블을 다시 지정합니다. 이것은 정점 ( m ... .pQ) 의 가능한 모든 순열을 매핑 한 다음을 사용하여 표준 순서에서 순서로 트리를 변환하여 수행됩니다 XdUQk. d나무 k입니다, 순열입니다.

그런 다음을 사용하여 모서리를 별도의 목록으로 분리 하고을 사용하여 c ... 2각 모서리 내의 정점을 SM정렬 S하고을 사용하여 트리 내의 모서리를 정렬하여 각 트리를 정식으로 표시합니다. 이 두 단계는 코드 mSSMcXdUQk2.pQ입니다.

이제 각 트리의 가능한 모든 레이블을 다시 구성한 목록 목록이 있습니다. 이 목록을로 정렬합니다 S. 두 가지 동형 나무는 모두 나무 그룹으로 레이블을 다시 지정할 수 있어야합니다. 이 사실을 사용하여 각 목록을로 문자열로 변환 `한 다음로 목록을 구성 {하고로 길이를 출력합니다 l.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.