Collat​​z Cousinsの計算


21

次のように、正の整数nに対して関数f(n)を定義します。

  • n / 2nが偶数の場合
  • 3 * n + 1nが奇数の場合

この関数を0より大きいnに繰り返し適用すると、結果は常に1に収束するように見えます(まだ誰も証明できていませんが)。このプロパティはCollat​​z予想と呼ばれます。

整数の停止時間を、1に達するまでCollat​​z関数fを通過する必要がある回数として定義します。最初の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

Collat​​z cousinsと同じ停止時間で数字のセットを呼び出しましょう。たとえば、5と32はCollat​​zのいとこであり、停止時間は5です。

あなたのタスク:非負の整数を取り、その整数に等しい停止時間を持つCollat​​zのいとこのセットを生成するプログラムまたは関数を作成します。

入力

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のために、3つの値[4、5、32]があるので、 "1 2 - - 4 - 1 - 2 - 4"
JPMC

1
@JPMCサイクルの回避は、停止時間の定義によって暗示されます。4の停止時間は5ではなく2です。2は「1に達する前にCollat​​z関数を通過する必要がある回数」であるためです。
DLosc

ああ、許して。複数のパスがそれにつながる可能性があるため、複数の停止時間を持つことができると考えていました。しかし、それは1からの構築に関するものであり、Nからの作業ではありません。それについて申し訳ありません。
-JPMC

1
もちろん、@ DLosc Pyth。
isaacg

1

回答:


7

Pyth、26 24 21バイト

Su+yMG-/R3fq4%T6G1Q]1

このコードはのために即座に実行されS=30ます。自分で試してみてください:デモンストレーション

5バイトを節約してくれた@isaacgに感謝します。

説明

私のコード1はCollat​​z関数で始まり、元に戻します。それはすべての数字にマッピングdするS-1にステップ2*dとを(d-1)/3。ただし、最後の1つは必ずしも有効ではありません。

                        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
- ... 1reduceの内側に合計を配置する場合、reduceをa .uにする必要も、-F外部にする必要もありません。2文字を保存します。
isaacg

@isaacgありがとう。以前のバージョンでは実際にこれを使用していましたが、エラーのデバッグ中に削除しました。
ジャクベ

3
私は自分の答えのために@isaacgを借りました。重複を削除するための最短のコードを見つけるために何時間も費やしましたが、これは断然最もエレガントなソリューションです。また、無効な商を破棄するためにタプルを使用することが本当に好きです。悲しいことに、CJamはタプルを持っていませんが、私は1に無効な商をマップするために管理しなかった
デニス

@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、唯一のパラメーターとしてCollat​​zのいとこのリストを返します。

アルゴリズムは単純な幅優先検索です。特定SのCollat​​zのいとこは、S-1via のCollat​​zのいとこから到達できる整数、2*nまたはviaから到達できる奇数(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

Python 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に感謝します。ドロップしてくれた@isaacgに感謝します~-。)

この変種はずっと短いですが、残念ながら指数関数的な分岐のために時間がかかりすぎます:

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 = 30、1秒未満で実行されます。
DLosc

1
@DLosc私はあなたのアイデアが好きで、それを改善しました:)
Sp3000

いいね!ここでの2以上バイトoff: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あははありがとう。私はまだ...かかわらず、より良い短絡方法があるように持って誓う
SP3000

~-整数除算を使用しているため、これは不要だと思います。
isaacg

5

CJam、29 26バイト

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

クレジットは、各反復後に1を削除するという彼のアイデアのために@isaacgに行き、2バイトを直接節約し、もう1バイトを間接的に節約しました。

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に即座にオンライン版に秒単位で実行されているJavaコンパイラ


これは、より大きな入力にどのくらいかかりますか? It should finish in seconds or minutes, not hours or days.
DLosc

ああ、なるほど。Pythonのバージョン私はN = 30のために約5時間を取るように見えた書いた
DLosc

最新バージョンはほぼ瞬時に実行されます。
オプティマイザー

6
コードにバグがあります。テストケースS=15は機能しません。
ジャクベ

3

Java 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にどれくらいかかるか?
ジオビット

これはJava 8でのみ機能しますか?javac 1.7.0_79Ubuntuで使用すると、多くの構文エラーが発生しました。
DLosc

@DLosc正しい; これについては投稿で言及します。
Ypnypn

ループの終端条件をi > 1 && ++n <= x(ドロップn++することもできます)に制限すると、さらに5文字だけ高速になります。S= 30の場合は約3分です。それは私が含まれている場合分の下で安全に剃らます.parallel()あまりにも、これはコード・ゴルフ...ですので、
HJK

1

Python 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各値の可能な先行を追加することにより、停止時間のセットを導き出します。tk

  • 2 * t 常に可能な前任者です。
  • tとして記述できる場合3 * u + 1uは奇数ではなく1、でuあり、同様に前任者です。

N = 30MacBook Proで実行するには約0.02秒かかります。


一般的にs.add(x)は、s|={x}代わりに行うことができるため、ゴルフでは不要です。また、ブラケット~-x(x+1)保存の代わりに使用します。しかし、そうでなければ、良い仕事:)
Sp3000

@ Sp3000ありがとう。2番目のs.add()ものは代入になり、式の一部になれないため、簡単に置き換えることはできません。それは最初のもののために働きます。forカウンターに基づくループは常に一種冗長なのにもあります。whileループを使用することで短縮できると思いましたが、同じ長さでまったく同じであることがわかりました。
レトコラディ

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

*バイトを節約するには、すべてのステップで追加する必要がksortありarray_keysました。私が持っていた唯一の他の選択肢は、その通話の小さなラッパー関数を作ることだったc()し、その後の呼び出しarray_keysksort結果には一度。しかし、まだきちんとした時間であるため、バイト数を少なくしてパフォーマンスを低下させることにしました。適切な並べ替えと処理を行わないと、S(30)の平均時間は0.07秒になります。

追加のバイトが多すぎることなく、適切な処理を1回だけ取得する賢い方法がある人は、教えてください!(私は自分の番号を配列キーとして保存しているため、array_keysandを使用しています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へようこそ!これはコードとゴルフの競合であるため、コードをできるだけ短くする必要があります。また、投稿に言語の名前を含めてください。
アレックスA.

{}ボタンを押してコードをフォーマットすることができます。これはあなたのために行いました。しかし、アレックスが言うように、言語名(C?)を追加して、ゴルフを試してみてください:)しかし、ようこそ!
Sp3000

@ Sp3000コードのフォーマットを手伝ってくれてありがとう
風の強い

機能fが正しく動作していません。でs=5、間違った結果がたくさん出てきます。if (r == s)return true;あるべきreturn (r==s)以来、fmeaninfulときにanytging戻りません(r < s)。また、私はあなたが宣言するべきだと思いiflong、それはいくつかの値のためにかなり迅速にオーバーフローすることから、。
デニス

@デニスありがとう:)それはあるべきですreturn (r==s);
風の強い
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.