Collatz 사촌 계산


21

양의 정수 n에 대해 함수 f (n) 을 다음과 같이 정의하십시오 .

  • N / 2 , 만약 n이 짝수
  • n 이 홀수 인 경우 3 * n + 1

이 함수를 0보다 큰 n에 반복해서 적용 하면 결과는 항상 1로 수렴하는 것으로 보입니다 (아직 아무도 그것을 증명할 수는 없었 음). 이 속성은 Collatz Conjecture라고 합니다.

정수의 정지 시간 을 Collatz 함수 f 가 1에 도달하기 전에 통과해야하는 횟수로 정의하십시오 . 처음 15 개의 정수의 정지 시간은 다음과 같습니다.

1  0
2  1
3  7
4  2
5  5
6  8
7  16
8  3
9  19
10 6
11 14
12 9
13 9
14 17
15 17

같은 중지 시간 Collatz 사촌 과 함께 숫자 세트를 호출합시다 . 예를 들어, 5와 32는 중지 시간이 5 인 Collatz 사촌입니다.

작업 : 음수가 아닌 정수를 사용하고 중지 시간이 해당 정수와 같은 Collatz 사촌 세트를 생성하는 프로그램 또는 함수를 작성하십시오.

입력

STDIN, ARGV 또는 함수 인수를 통해 제공되는 음이 아닌 정수 S.

산출

중지 시간이 S 인 모든 숫자의 목록은 오름차순으로 정렬 됩니다 . 리스트는 프로그램에 의해 출력되거나 함수에 의해 리턴되거나 출력 될 수 있습니다. 출력 형식은 유연합니다. 공백으로 구분하거나 줄 바꾸기로 구분하거나 언어의 표준 목록 형식을 사용하면 숫자를 쉽게 구분할 수 있습니다.

요구 사항

제출물은 S ≤ 30에 대해 정확한 결과를 제공해야합니다. 몇 시간 또는 며칠이 아니라 몇 초 또는 몇 분 안에 완료되어야합니다.

0  -> 1
1  -> 2
5  -> 5, 32
9  -> 12, 13, 80, 84, 85, 512
15 -> 22, 23, 136, 138, 140, 141, 150, 151, 768, 832, 848, 852, 853, 904, 906, 908, 909, 5120, 5376, 5440, 5456, 5460, 5461, 32768

다음은 S = 30 의 출력 요점입니다 .

이것은 : 바이트 단위의 최단 프로그램이 이깁니다. 행운을 빕니다!


사이클은 무엇입니까? 나는 사이클 회피에 대한 언급을 보지 못했다. S = 5의 경우, "
1-2-4-1-2-4

1
@JPMC 사이클 회피는 정지 시간의 정의에 의해 암시됩니다. 4의 중지 시간은 5가 아니라 2입니다. 2는 "1에 도달하기 전에 Collatz 함수를 통과해야하는 횟수"이기 때문입니다.
DLosc

아, 용서하세요 여러 경로로 이어질 수 있기 때문에 여러 중지 시간이있을 수 있다고 생각했습니다. 그러나 그것은 N에서 일하지 않고 1에서 구축하는 것과 관련이 있습니다. 미안합니다.
JPMC

1
물론 @DLosc Pyth.
isaacg

답변:


7

Pyth, 26 24 21 바이트

Su+yMG-/R3fq4%T6G1Q]1

이 코드는에 대해 즉시 실행됩니다 S=30. 직접 해보십시오 : 데모

5 바이트를 절약 한 @isaacg에게 감사합니다.

설명

내 코드 1는 Collatz 기능으로 시작 하고 실행 취소합니다. 단계 d의 모든 숫자 S-12*d및에 매핑합니다 (d-1)/3. 그래도 마지막은 항상 유효하지는 않습니다.

                        implicit: Q = input number
                   ]1   start with G = [1]
 u                Q     apply the following function Q-times to G:
                          update G by
   yMG                      each number in G doubled
  +                       +
          fq4%T6G           filter G for numbers T, which satisfy 4==T%6
       /R3                  and divide them by 3
      -          1          and remove 1, if it is in the list
                            (to avoid jumping from 4 to 1)
S                       sort the result and print

의 아름다운 사용법입니다 -F.
isaacg

1
- ... 1리듀서 내부에 합계 를 두는 경우 .u리듀서가 -F외부 또는 외부 일 필요는 없습니다 . 2자를 저장합니다.
isaacg

@isaacg 감사합니다. 실제로 이전 버전에서는 이것을 가지고 있었지만 오류를 디버깅하는 동안 제거했습니다.
Jakube

3
나는 내 자신의 대답을 위해 @isaacg를 빌렸다. 중복을 제거하기위한 가장 짧은 코드를 찾으려고 몇 시간을 보냈지 만 이것이 가장 우아한 해결책입니다. 또한, 나는 당신이 유효하지 않은 몫을 버리는 튜플의 사용을 정말로 좋아합니다. 슬프게도 CJam에는 튜플이 없지만 유효하지 않은 몫을 1로 매핑했습니다.
Dennis

@Jakube는와 q4%d6동일 !%hhd6하지만 1 자 더 짧습니다.
isaacg

8

Mathematica, 98 92 89 바이트

이 솔루션은 S = 30즉시 해결됩니다 .

(p={0};l={1};Do[l=Complement[##&@@{2#,Mod[a=#-1,2]#~Mod~3~Mod~2a/3}&/@l,p=p⋃l],{#}];l)&

이것은 S유일한 매개 변수로 사용하고 Collatz 사촌 목록을 반환 하는 명명되지 않은 함수 입니다.

이 알고리즘은 간단한 너비 우선 검색입니다. 주어진 SCollatz 사촌은 Collatz 사촌에서을 S-1통해 도달 할 수있는 모든 정수 2*n또는 을 통해 도달 할 수있는 홀수 (n-1)/3입니다. 또한 단계 후 처음으로 도달 한 정수만 생성 S하므로 이전의 모든 사촌을 추적 p하고 결과에서 제거합니다. 어쨌든 우리는 그렇게하고 있기 때문에 이전의 모든 사촌 ( 단계 뿐만 아니라 S-1) 의 단계를 계산하여 몇 바이트를 절약함으로써 몇 바이트를 절약 할 수 있습니다 (이는 약간 느리지 만 필요한 것은 눈에 띄지 않습니다 S).

약간 더 읽기 쉬운 버전이 있습니다 :

(
  p = {0};
  l = {1};
  Do[
    l = Complement[
      ## & @@ {2 #, Mod[a = # - 1, 2] #~Mod~3~Mod~2 a/3} & /@ l,
      p = p ⋃ l
    ]~Cases~_Integer,
    {#}
  ];
  l
) &

5

파이썬 2, 86 83 75 73 71 바이트

f=lambda n,k=1:sorted([k][n:]or(k>4==k%6and f(n-1,k/3)or[])+f(n-1,k*2))

처럼 전화하십시오 f(30). n = 30거의 즉각적입니다.

( k사촌 목록이 아닌 숫자와 몇 바이트로 되풀이되는 아이디어에 대해 @DLosc에게 감사합니다 ~-.

이 변형은 훨씬 짧지 만 불행히도 지수 분기로 인해 너무 오래 걸립니다.

f=lambda n,k=1:sorted([k][n:]or(k>4==k%6)*f(n-1,k/3)+f(n-1,k*2))

흥미 롭습니다. 원래 솔루션은 매우 비슷하지만 (몇 가지 최적화를 수행하면) 2 바이트가 짧아집니다 f=lambda d,n=1:d and sorted(sum((c(d-1,x)for x in[n*2]+[~-n/3][:n>4==n%6]),[]))or[n]. 함수 호출에서는 효율성이 떨어지지 만 여전히 n = 301 초 안에 수행됩니다.
DLosc

1
@DLosc 나는 당신의 아이디어를 좋아하고 그것을 더 좋게 만들었습니다 :)
Sp3000

좋은! 2 바이트가 더 있습니다 :f=lambda n,k=1:sorted([k][n:]or(k>4==k%6and f(n-1,~-k/3)or[])+f(n-1,k*2))
DLosc

@DLosc Ahaha 감사합니다. 그래도 더 나은 단락 방법이 있어야 맹세합니다 ...
Sp3000

~-정수 나누기를 사용하고 있기 때문에 불필요 하다고 생각합니다 .
isaacg

5

CJam, 29 26 바이트

Xari{{2*_Cmd8=*2*)}%1-}*$p

크레디트는 각 반복 후 1을 제거하려는 아이디어로 @isaacg로 이동하여 2 바이트를 직접 저장하고 다른 바이트는 간접적으로 저장했습니다.

CJam 통역사 에서 온라인으로 사용해보십시오 (1 초 이내에 완료해야 함).

작동 원리

Xa       e# Push A := [1].
ri{      e# Read an integer from STDIN and do the following that many times:
  {      e# For each N in A:
    2*   e#     Push I := (N * 2) twice.
    _Cmd e#     Push (I / 12) and (I % 12).
     8=  e#     Push K := (I % 12 == 8).

         e#     (K == 1) if and only if the division ((N - 1) / 3) is exact and
         e#     yields an odd integer. In this case we can compute the quotient 
         e#     as (I / 12) * 2 + 1.

    *2*) e#     Push J := (I / 12) * K * 2 + 1.

         e#     This yields ((N - 1) / 3) when appropriate and 1 otherwise.
  }%     e# Replace N with I and J.
  1-     e# Remove all 1's from A.

         e# This serves three purposes:

         e# 1. Ones have been added as dummy values for inappropriate quotients.

         e# 2. Not allowing 1's in A avoids integers that have already stopped
         e#    from beginning a new cycle. Since looping around has been prevented,
         e#    A now contains all integers of a fixed stopping time.

         e# 3. If A does not contain duplicates, since the maps N -> I and N -> J
         e#      are inyective (exluding image 1) and yield integers of different
         e#      parities, the updated A won't contain duplicates either.

}*       e#
$p       e# print(sort(C))

4

CJam, 35 바이트

1]ri{_"(Z/Y*"3/m*:s:~\L+:L-_&0-}*$p

곧 설명하겠습니다. 이것은 "꽤 직설적 인"접근 방식보다 훨씬 빠른 버전입니다 (편집 기록에서 확인).

온라인 여기 시도 에 대해 N = 30어느에 즉시 온라인 버전에 초 단위로 실행되며 자바 컴파일러


더 큰 입력에 시간이 얼마나 걸립니까? It should finish in seconds or minutes, not hours or days.
DLosc

아, 알겠습니다 필자가 작성한 Python 버전은 N = 30에 약 5 시간이 소요되는 것으로 보였습니다.
DLosc

최신 버전은 거의 즉시 실행됩니다.
Optimizer

6
코드에 버그가 있습니다. 테스트 사례 S=15가 작동하지 않습니다.
Jakube

3

자바 8, 123

x->java.util.stream.LongStream.range(1,(1<<x)+1).filter(i->{int n=0;for(;i>1;n++)i=i%2<1?i/2:3*i+1;return n==x;}).toArray()

x30 프로그램 15 분 29 초 정도 걸립니다.

넓히는

class Collatz {
    static IntFunction<long[]> f =
            x -> java.util.stream.LongStream.range(1, (1 << x) + 1).filter(i -> {
                int n = 0;
                for (; i > 1; n++)
                    i = i % 2 < 1 ? i / 2 : 3 * i + 1;
                return n == x;
            }).toArray();

    public static void main(String[] args) {
        System.out.println(Arrays.toString(f.apply(15)));
    }
}

궁금한 점은 S = 30까지 얼마나 걸립니까?
Geobits

이것은 Java 8에서만 작동합니다. 맞습니까? javac 1.7.0_79Ubuntu에서 사용하면 많은 구문 오류가 발생했습니다.
DLosc

@DLosc 올바른; 나는 포스트에서 그것을 언급 할 것이다.
Ypnypn

루프 터미널 조건을 i > 1 && ++n <= x( n++너무 떨어 뜨릴 수 있음)로 제한하는 것은 5 자만 더 빠를수록 더 빠릅니다. S = 30은 약 3 분입니다. 내가 포함하면 1 분 안에 안전하게 면도됩니다 .parallel(). 그러나 이것이 코드 골프이기 때문에 ...
hjk

1

파이썬 2, 118 바이트

글쎄, @ Sp3000의 솔루션을 본 후 최고의 Python 점수에 도달하지 못할 것이라고 생각했습니다. 그러나 그것은 재미있는 작은 문제처럼 보였으므로 어쨌든 독립적 인 솔루션을 시도하고 싶었습니다.

s={1}
for k in range(input()):
 p,s=s,set()
 for t in p:s.add(2*t);t>4and(t-1)%6==3and s.add((t-1)/3)
print sorted(s)

공백을 제거하기 전에 같은 것 :

s={1}
for k in range(input()):
    p,s=s,set()
    for t in p:
        s.add(2 * t)
        t > 4 and (t - 1) % 6 == 3 and s.add((t - 1) / 3)
print sorted(s)

이것은 광범위한 첫 번째 검색을 매우 직접 구현 한 것입니다. 각 단계에서는, 정지 시간과의 세트를 가지고 k, 시간 정지하여 세트를 도출 k + 1각 값의 가능한 추가하여 선행 t단계에서 집합하여 k:

  • 2 * t 항상 전임자입니다.
  • 경우 t로서 기록 될 수있다 3 * u + 1여기서 u되지 홀수 1u뿐만 아니라 선행된다.

N = 30MacBook Pro 에서 실행하는 데 약 0.02 초가 걸립니다 .


일반적으로 대신 s.add(x)골프를 할 수 있기 때문에 골프 에서는 불필요 s|={x}합니다. 또한 대괄호 ~-x대신 (x+1)저장을 사용하십시오 . 그러나 그렇지 않으면, 좋은 직업 :)
Sp3000

@ Sp3000 감사합니다. 두 번째 s.add()는 과제가 되었기 때문에 쉽게 바꿀 수 없으며 더 이상 표현식의 일부가 될 수 없습니다. 첫 번째 작동합니다. for카운터를 기반으로 한 루프는 항상 자세합니다. while루프 를 사용하여 단축 할 수 있다고 생각 했지만 정확히 동일한 길이로 나타났습니다.
Reto Koradi

for루프 대신에, 다른 방법으로 입력을 사용하지 않기 때문에 아마도 exec"..."*input()대신에 다음을 수행 할 수 있습니다 :)
Sp3000

1

PHP 5.4+, 178 바이트

함수

function c($s,$v=1,$p=[],&$r=[]){$p[]=$v;if(!$s--){return$r[$v][]=$p;}c($s,$v*2,$p,$r);is_int($b=($v-1)/3)&!in_array($b,$p)&$b%2?c($s,$b,$p,$r):0;ksort($r);return array_keys($r);}

테스트 및 출력

echo "0 - ".implode(',',c(0)).PHP_EOL;
// 0 - 1
echo "1 - ".implode(',',c(1)).PHP_EOL;
// 1 - 2
echo "5 - ".implode(',',c(5)).PHP_EOL;
// 5 - 5,32
echo "9 - ".implode(',',c(9)).PHP_EOL;
// 9 - 12,13,80,84,85,512
echo "15 - ".implode(',',c(15)).PHP_EOL;
// 15 - 22,23,136,138,140,141,150,151,768,832,848,852,853,904,906,908,909,5120,5376,5440,5456,5460,5461,32768

S (30)은 0.24 초 * 안에 실행되며 732 개의 요소를 반환합니다. 부부는

86,87,89,520,522,524,525,528, [ ... ] ,178956928,178956960,178956968,178956970,1073741824

* 나는 추가했다 바이트에 저장하려면 ksortarray_keys모든 단계에서. 내가 가진 유일한 다른 선택의 여지는 전화 작은 래퍼 함수를 만드는 것이 었습니다 c()다음 통화 array_keysksort결과에 한 번. 그러나 여전히 시간이 너무 짧아서 낮은 바이트 수에 대한 성능 적중을 결정했습니다. 적절한 분류 및 처리가 없으면 시간은 0.07 초입니다. S (30)의 평균 입니다.

너무 많은 추가 바이트없이 한 번만 적절한 처리를 얻는 영리한 방법이 있다면 알려주십시오! (I는, 배열 키로의 따라서 사용이 내 번호를 저장 array_keys하고 ksort)


0

C 언어

#include <stdio.h>
#include <limits.h>    
const int s = 30;

bool f(long i)
{
    int r = 0;
    for(;;)
        if (i < 0 || r > s) return false;
        else if (i == 1) break;
        else{r ++;i = i % 2 ? 3*i + 1 : i/2;}
    return (r==s);
}

void main(){
    for(long i = 1; i < LONG_MAX; i++) if (f(i)) printf("%ld ", i);
}

5
PPCG에 오신 것을 환영합니다! 이것은 코드 골프 경쟁 이기 때문에 코드를 최대한 짧게 만들고 싶을 것입니다. 또한 게시물에 언어 이름을 포함 시키십시오.
Alex A.

당신은 칠 수 {}내가 당신을 위해 수행 한 코드를 포맷 버튼을. 그러나 Alex가 말했듯이 언어 이름 (C?)을 추가하고 골프를 타보십시오 :) 그러나 환영합니다!
Sp3000

@ Sp3000 코드 포맷을 도와 주셔서 감사합니다
바람

기능 f이 제대로 작동하지 않습니다. 를 사용하면 s=5잘못된 결과가 많이 발생합니다. if (r == s)return true;해야 return (r==s)하기 때문에, f때 meaninful anytging 반환하지 않습니다(r < s) . 또한, 나는 당신이 선언해야한다고 생각 iflong는 어떤 값을 꽤 빨리 오버 플로우 때문에.
Dennis

@Dennis 감사합니다 :) 그것은return (r==s);
바람이
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.