운율 체계 열거


26

"리듬 구성표"는에 대한 문자열 az, 첫 번째 문자가에서 시작하여 오름차순 (간격없이)입니다 a. 예를 들어 (첫 번째 항목이 표시된 상태) :

abccdbebdcfa
^^^ ^ ^   ^

길이의 운율의 수 N벨 수에 의해 주어진다 B(N). ( OEIS A000110 )

도전

당신의 임무는 이러한 운율 체계의 열거, 즉 정수에서 운율 체계로의 형용사 매핑을 구현하는 것입니다. 양의 정수 N <= 26와 음이 아닌 정수가 주어집니다 0 <= i < B(N). 또는 range를 사용할 수 있습니다 1 <= i <= B(N). N모든 길이 i가 다른 문자열을 생성하도록 length의 운율 체계를 출력해야 합니다.

STDIN (또는 가장 가까운 대안), 명령 행 인수 또는 함수 인수를 통해 입력을 받고 STDOUT (또는 가장 가까운 대안), 함수 리턴 값 또는 함수 (out) 매개 변수를 통해 결과를 출력하는 프로그램 또는 함수를 작성할 수 있습니다.

소문자 또는 대문자를 일관되게 사용할 수 있습니다.

귀하의 코드는 유효한 시간에 유효한 입력을 처리 할 수 ​​있어야합니다 (예 : 최악의 경우 몇 시간넘지 않아야 함 ). 이것은 느린 언어에서도 기하 급수적으로 (소규모의 경우) 확장되는 솔루션을 허용 하지만 (즉 ) 와 선형으로 확장되는 솔루션은 금지해야 합니다. 특히, 이는 스키마를 버릴 때까지 모든 유효한 운율 체계를 반복 할 수 없다는 것을 의미합니다 .N = 26iNiB(N)Ni

표준 규칙이 적용됩니다.

ito 체계 의 정확한 할당 (즉, 주어진 체계의 순서 N)은 귀하에게 달려 있습니다. 그러나 사전 식 순서를 선택했다고 가정하면 솔루션이 다음 표와 일치해야합니다 ( -잘못된 입력을 나타냄).

N\i 1    2    3    4    5    6    7    8    9    10   11   12   13   14   15
1   a    -    -    -    -    -    -    -    -    -    -    -    -    -    -
2   aa   ab   -    -    -    -    -    -    -    -    -    -    -    -    -
3   aaa  aab  aba  abb  abc  -    -    -    -    -    -    -    -    -    -
4   aaaa aaab aaba aabb aabc abaa abab abac abba abbb abbc abca abcb abcc abcd

다음은 주어진 길이에 대해 유효한 모든 리듬 구성표를 생성 하는 짧은 CJam 스크립트 입니다 (하지만 10 회 이상 시도하지 않으면 잠시 기다립니다).

관련 도전


5
N상당히 사소한 것으로 판명되지 않고 그것을 발견하기에는 너무 어리 석 다면 (골프) 다항식 솔루션에 현상금을 넣을 수 있습니다.
Martin Ender

현상금은 다항식 시간 솔루션에 적합하지만 시간 제한을 충족하는 지수 시간 솔루션을 계속보고 싶습니다. (내 자신의 Mathematica 참조 구현은 현재 여전히 도전에서 이길 것입니다.)
Martin Ender

B (26)은 64 비트 정수에 맞지 않는 가장 작은 Bell 번호입니다. Meanie. :-(
Anders Kaseorg

답변:


3

CJam, 68 66 바이트

r~:W)1a*{__(;\);_,,.*.+}W(*r~{X@\=_2$\/:CX<!{X:C):X;}&C*-C'a+o}W*;

온라인으로 사용해보십시오.

이것이 내 첫 CJam 프로그램입니다. 그것은 내 Perl 솔루션의 포트로 시작되었으며 처음에는 130 바이트 이상이었습니다. 더 골프 제안을 환영합니다.

내 Perl 프로그램과 마찬가지로 두 부분으로되어 있습니다.

Part 1:
r~:W                                         | Read the first input (n) and store it in W
    )1a*                                     | Create an array of n+1 1s
        {              }W(*                  | Repeat n-1 times:
         __                                  | Duplicate array twice
           (;\);                             | Remove first element of 1st array. Swap
                                             | arrays. Remove last element of 2nd array
                _,,                          | Duplicate array. Count items. Create range
                   .*.+                      | Multiply arrays. Add 1st array to result

Part 2:
r~                                           | Read the second input (i)
   {                                  }W*    | Repeat n times:
    X@                                       | Push y (initially 1). Bring item 2 (last array) to top
     \=                                      | Swap top two items. Pop array[y] (v)
       _2$                                   | Duplicate v. Copy item 2 (i) to top
          \/:CX                              | Swap i & v. i/v. Store in C (c). Push y
               <!{       }&                  | If !(i/v < c):
                  X:C):X;                    | c = y. ++y (store in X)
                           C*-C'a+o          | i -= c * v. Push y. Push "a". Add c. Print
                                         ;   | Discard top item (integer 0)

Part 1에서 생성 한 배열을 디버그하려면 Part 1 ]_`o~과 2 사이에 추가하십시오 . n이 5인 경우 배열은 다음과 같습니다 [[1 1 1 1 1 1] [1 2 3 4 5] [2 5 10 17] [5 15 37] [15 52]]. 각 배열의 0 인덱스는 사용되지 않으며 오프셋을 계산할 필요가 없어 더 쉽게 만들 수 있습니다. 배열은 다음과 같이 계산됩니다.

[2 5 10 17] [2 5 10 17] [2 5 10 17]        | Duplicate twice
[2 5 10 17] [2 5 10 17] [5 10 17]          | Discard first item of array
[2 5 10 17] [5 10 17] [2 5 10 17]          | Swap last two arrays
[2 5 10 17] [5 10 17] [2 5 10]             | Discard last item of array
[2 5 10 17] [5 10 17] [2 5 10] [2 5 10]    | Duplicate array
[2 5 10 17] [5 10 17] [2 5 10] 3           | Count items in array
[2 5 10 17] [5 10 17] [2 5 10] [0 1 2]     | Integer to range 0 - n-1
[2 5 10 17] [5 10 17] [0 5 20]             | Multiply arrays [2*0 5*1 10*2]
[2 5 10 17] [5 15 37]                      | Add arrays [5+0 10+5 17+20]

다음 배열을 계산하는 동안 이전 배열의 사본을 유지합니다. 배열은 Part 2에서 역순으로 읽고 버립니다.


13

파이썬 2, 153

u=[1]*999;i=60;exec"u[i]=i%30*u[i-30]+u[i-29];i+=1;"*900
def x(l,n,a=0):m=u[30*l+a];c=n>=a*m;return'.'*l and chr(65+min(n/m,a))+x(l-1,[n%m,n-m*a][c],a+c)

알파벳 순서와 0 기반 색인을 사용합니다.

하자 l문자의 접미사의 길이를 나타내며 a앞 부분에 사용 된 고유 한 문자의 수를 나타낸다. 그런 다음 p(l,a)나머지 문자를 선택하는 방법의 수를 계산 하는 함수 는 40 바이트 일 수 있습니다.

p=lambda l,a:l<1or a*p(l-1,a)+p(l-1,a+1)

그러나이 방법은 시도하기에는 너무 느리므로 필요한 값이 미리 계산되어 u배열에 저장됩니다 . 다음 문자가 중 하나 인 경우, 계산의 각 단계에서 a사용되는 이미 N = K * P (1 - 1, a) + N ' 여기서 k는 알파벳 0 인덱싱 편지이며, N'n나머지 문자에 대한 정보를 포함하는 다음 함수 호출 의 값 새로운 문자가 사용되면, n = a * p (l-1, a) + n ' 입니다.


1
최악의 경우 입력하는데 얼마나 걸립니까?
Michael Klein

1
@MichaelKlein 무시할만한 시간입니다.
feersum

이것은 정확히 내가 계획 한 것입니다 (JS로 수행했을 것 제외). 좋은 작업! +1
ETHproductions

11

하스켈 (GHC 7.10), 150 바이트

s=(1,\_->[]):s
k!((y,b):l@((x,a):_))|let h i|i<x=k:a i|(p,q)<-divMod(i-x)y=p:b q=(x+k*y,h):(k+1)!l
n#i=(['a'..]!!).fromEnum<$>snd(iterate(0!)s!!n!!0)i

연산자 는 length의 제로 (인덱싱 된) 운율 체계를 n # i계산합니다 . 자동 메모에 대한 Haskell의 게으른 무한 목록을 활용하여 O (n²) (큰 정수) 연산으로 실행됩니다. 샘플 실행 :in

*Main> 26 # 0
"abcdefghijklmnopqrstuvwxyz"
*Main> 26 # 1
"abcdefghijklmnopqrstuvwxya"
*Main> 26 # 2
"abcdefghijklmnopqrstuvwxyb"
*Main> 26 # 49631246523618756271
"aaaaaaaaaaaaaaaaaaaaaaaabb"
*Main> 26 # 49631246523618756272
"aaaaaaaaaaaaaaaaaaaaaaaaab"
*Main> 26 # 49631246523618756273
"aaaaaaaaaaaaaaaaaaaaaaaaaa"
*Main> [1 # i | i <- [0..0]]
["a"]
*Main> [2 # i | i <- [0..1]]
["ab","aa"]
*Main> [3 # i | i <- [0..4]]
["abc","aba","abb","aab","aaa"]
*Main> [4 # i | i <- [0..14]]
["abcd","abca","abcb","abcc","abac","abaa","abab","abbc","abba","abbb","aabc","aaba","aabb","aaab","aaaa"]

(최대 N이 26 대신 25 인 경우 .fromEnumB (25)가 64 비트에 적합하므로 제거 할 수 있습니다 Int.)


1
좋아 보인다. 쉽게 구울 수 있도록 덜 골프 버전을 추가 하시겠습니까?
Michael Klein

4

Perl 257 + 1 (-p 플래그) = 258

Perl 182 + 10 (-pMbignum 플래그) = 192

($n,$i)=split;@m=[@a=(1)x($n+1)];while($a[2]){push@m,[@a=map{$a[$_]*$_+$a[$_+1]}0..$#a-1]}$_='';$y=1;while($w=pop@m){$c=int($i/($v=$$w[$y]));$c=$y++if($c>=$y);$i-=$c*$v;$_.=chr$c+65}

많은 바이트를 절약 해 준 dev-nul 덕분에 ! CJam 버전을 통해 배운 내용을 바탕으로 다시 작성했습니다.

알파벳 순서로 운율을 계산합니다 (0 색인).

두 부분 : 파트 1은 128 90 바이트이고 파트 2에 대한 행렬을 계산합니다. 파트 2는 129 92 바이트이며 각 문자를 계산하는 간단한 수학을 수행합니다. 행렬을 제거하고 두 개의 간단한 숫자로 교체 할 수 있다면 각 숫자에 대한 행렬을 통한 단일 경로를 계산하고 많은 바이트를 절약 할 수 있습니다! 분명히, 그 아이디어는 작동하지 않습니다!

불행히도 i9007199254740992보다 높은 값에는 올바른 운율을 출력하지 않지만 낮은 값에는 아름답게 작동합니다! 11 바이트의 비용으로 Bignum 라이브러리를 추가했습니다. 명령 줄에서로 실행됩니다 perl -pMbignum bell-rhyme.pl. -pMbignum = 10 바이트 모든 입력 값에 대해서도 매우 빠릅니다.


2

Oracle SQL 11.2, 412 284 283 바이트

WITH a AS(SELECT CHR(96+LEVEL)d,LEVEL b FROM DUAL CONNECT BY LEVEL<=:i),v(s,c,n)AS(SELECT d,1,1 FROM a WHERE b=1 UNION ALL SELECT s||d,b,LENGTH(REGEXP_REPLACE(s||d,'([a-z])\1+','\1'))FROM v,a WHERE(b<=n OR b=c+1)AND LENGTH(s)<:n)SELECT s FROM v WHERE:n=LENGTH(s)AND:i<=:n ORDER BY 1;

불행히도 최대 길이는 8입니다. ORA-01489 : 문자열 연결 결과가 너무 깁니다.

언 골프

WITH a AS(SELECT CHR(96+LEVEL)d,LEVEL b FROM DUAL CONNECT BY LEVEL<=:i),
v(s,c,n) AS
(
  SELECT d,1,1 FROM a WHERE b=1
  UNION ALL
  SELECT s||d,b,LENGTH(REGEXP_REPLACE(s||d,'([a-z])\1+','\1')) 
  FROM v,a 
  WHERE (b<=n OR b=c+1) AND LENGTH(s)<:n
)
SELECT s FROM v WHERE LENGTH(s)=:n AND :i<=:n ORDER BY 1;

a 뷰는 a 열에 : i 문자를 생성하고 b에 값을 생성합니다.

재귀 뷰 v는 매개 변수 v, c에 사용 된 마지막 문자 값 및 n에 사용 된 가장 큰 문자 값으로 구성된 문자열을 사용합니다. n 매개 변수는 중복 문자가없는 문자열의 길이와 같습니다. 즉 정규 표현식입니다.

문자 값이 <= 이미 사용 된 가장 큰 문자의 값이거나 다음에 사용할 문자 인 경우 유효합니다.

어떻게 든 쿼리를 실행하려면 LENGTH (s) <: n 부분이 필요합니다. 쿼리 작동 방식에 무언가가 빠져 있어야합니다.

기본 SELECT는 유효하지 않은 입력과 대상 길이에 도달하기 전에 작성된 짧은 문자열을 필터링하여 처리합니다.

412 바이트 버전

WITH a AS(SELECT * FROM(SELECT d,b,ROW_NUMBER()OVER(PARTITION BY b ORDER BY d)l FROM(SELECT CHR(64+DECODE(MOD(LEVEL,:i),0,:i,MOD(LEVEL,:i)))d,CEIL(LEVEL/:i)b FROM DUAL CONNECT BY LEVEL<=:i*:n))WHERE l<=b),v(s,c,p)AS(SELECT d,1,l FROM a WHERE b=1 UNION ALL SELECT s||d,c+1,l FROM v,a WHERE c+1=b AND(l<=LENGTH(REGEXP_REPLACE(s,'([A-Z])\1+','\1'))OR l=p+1))SELECT s FROM v WHERE LENGTH(s)=:n AND :i<=:n ORDER BY 1;

26으로 412 바이트 쿼리를 시도하지 마십시오. 적어도 맥북의 도커 컨테이너에서 실행중인 xe 버전에서 데이터베이스를 제한 모드로 설정합니다. 직장에서 엑사 데이터를 시험해 볼 수는 있지만 슬프게도 여전히 생계를 위해 일해야합니다.


0

수학, 136 바이트

(For[j=2^#-1;t=#2,c=1;m=0;x=t;r=If[#>0,++m,c*=m;d=x~Mod~m+1;x=⌊x/m⌋;d]&/@j~IntegerDigits~2;;c<=t,t-=c;--j];FromCharacterCode[r+64])&

완벽을 기하기 위해 여기에 골프 참조 구현이 있습니다. 기존 답변과 달리 이것은 다항식 시간 ( N기본 2와 함께 지수)으로 실행되지 않지만 시간 제약 조건을 충족시키지 않습니다 (가장 최악의 경우 여전히 30 분 미만으로 실행됩니다).

아이디어는 이것입니다 :

  • 각 운율 체계마다 최대 문자가 지금까지 증가하는 위치를 식별 할 수 있습니다.

    ABCDEFGHDIJDEKBBIJEIKHDFII
    ^^^^^^^^ ^^  ^
    

    이러한 표시를 이진 숫자로 취급하면 이러한 모든 구조를 쉽게 반복 할 수 있습니다. 2 n-1 에서 2 n (또는 다른 방식으로) 을 반복해야합니다 .

  • 이러한 각 구조에 대해 그러한 문자열의 수를 쉽게 결정할 수 있습니다. 표시 사이의 간격 만 자유롭게 선택할 수 있으며 간격 앞의 최대 값은 각 위치에서 유효한 문자 수를 나타냅니다. 이것은 간단한 제품입니다. 이 숫자가보다 작 으면 i에서을 뺍니다 i. 그렇지 않으면 요청 된 운율 체계의 구조를 찾았습니다.
  • 주어진 구조의 체계를 열거하기 위해, 우리는 단순히 i(또는 나머지를) 혼합 기준 숫자로 나타내며 , 숫자의 가중치는 나머지 위치에서 허용되는 문자 수에 의해 결정됩니다.

이것이 메모 또는 사전 계산이 필요하지 않기 때문에 제출 된 다른 언어 중 더 짧은 솔루션을 허용하는지 궁금합니다.

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