最短のゴロム定規を見つける


15

ゴロム定規は、負の整数のセットであるため、セット内の整数の2つのペアが同じ距離だけ離れていることはありません。

たとえば[0, 1, 4, 6]、このセットの2つの整数間の距離はすべて一意であるため、Golombルーラーです。

0, 1 -> distance 1
0, 4 -> distance 4
0, 6 -> distance 6
1, 4 -> distance 3
1, 6 -> distance 5
4, 6 -> distance 2

(翻訳は自明であるので)この課題では単純化のために、我々は課すゴロム定規があること、常に番号が含まれています0(前の例がないもの)。

このセットは長さがあるので4、これはゴロムの秩序 支配者だと言い4ます。このセット(またはセット内に0常にあるため、要素)の最大距離はです6。したがって、これは長さの ゴロム定規であると言い6ます。

あなたのタスク

短い長さの 50100含む)順序の Golomb定規を見つけるあなたが見つけることができるように。見つけたルーラーは最適である必要はありません(以下を参照)。

最適性

順序Nのゴロム定規は、他の順序のゴロム定規がない場合に最適であると言われていますNは、より短い長さの。

最適なゴロム定規は28未満の次数で知られていますが、次数が増えるにつれて最適性を見つけて証明することはますます難しくなります。

したがって、次の注文のいずれかに対して最適なゴロム定規を見つけることは期待されていません 50100(あなたは、彼らが最適であることを証明できることを期待し、さらに少ないです)。

プログラムの実行に時間制限はありません。

ベースライン

以下のリストは、単純な検索戦略で評価さ50れた100(順序で)からまでのGolombルーラーの長さのリストです(このリストは@PeterTaylorに感謝します)。

[4850 5122 5242 5297 5750 5997 6373 6800 6924 7459 7546 7788 8219 8502 8729 8941 9881 10199 10586 10897 11288 11613 11875 12033 12930 13393 14046 14533 14900 15165 15687 15971 16618 17354 17931 18844 19070 19630 19669 20721 21947 22525 23290 23563 23880 24595 24767 25630 26036 26254 27218]

これらすべての長さの合計は 734078です。

得点

あなたのスコアが間のすべてのあなたのゴロム定規の長さの合計になります50100の間ゴロム定規の長さの合計で割った値、50および100ベースラインで:734078

特定の注文のGolombルーラーが見つからなかった場合、その特定の注文のベースラインの長さの2倍を使用して、同じ方法でスコアを計算します。

最も低いスコアの答えが勝ちです。

同点の場合、2つの回答が異なる最大の順序の長さが比較され、最も短い順序が優先されます。すべての注文で両方の回答の長さが同じ場合、最初に投稿された回答が優先されます。


2
関連。(2Dで同じ課題。)
マーティンエンダー


ルーラーを50〜100と言うとき、範囲は[50、100)ですか?そうではないため100定規を含みますか?ベースラインには50個の要素しか含まれていないためです。
orlp

1
サイドノート:ゴロムの秩序の支配者の最小の長さnn(n-1)/2であり、それは正の違いがいくつあるかです。したがって、このチャレンジで可能な最小スコアは147050/734078 > 0.2003193です。
グレッグマーティン

2
@GregMartinありがとうございます。ただし、これは「可能な限り最小のスコア」ではなく、可能な限り最小のスコアの下限です。
1

回答:


8

C#、259421/734078〜= 0.3534

方法

私はついに、射影場法(歌手の方法)の多かれ少なかれ読みやすい説明を見つけました 、一般化されたシドンセットの構築でまだ少し改善できると思います。私が読んだ他の論文が伝えたよりも、アフィンフィールド法(ボーズの方法)に似ていることがわかりました。

q=paFqベースフィールドとします。

Fq2g2Fq2kFq

{ag2akg2Fq}
q21q21

F(q3)g3Fq3kFq

{0}{ag3akg3Fq}
q2+q+1。アフィンフィールド法と同じ方法でモジュラー乗算を行うと、さらにルーラーを取得できます。

注は、それらの間、これらのメソッドは、与えることを最もよく知られている値 16トマスRokickiとギルドゴンよりも、すべての長さの大きいのためにしている$、250の報酬を提供しますため、この答えを打つ誰もが金銭のためである40000に長さ36のためにそれらを打つ人のために賞。

コード

C#はあまり慣用的ではありませんが、Monoの古いバージョンでコンパイルするために必要です。また、引数のチェックにもかかわらず、これは製品品質のコードではありません。私は型に満足していませんが、C#にはそれに対する本当に良い解決策があるとは思いません。たぶん非常識なテンプレートを使用したF#またはC ++の場合があります。

using System;
using System.Collections.Generic;
using System.Linq;

namespace Sandbox {
    class Program {
        static void Main(string[] args) {
            var winners = ComputeRulerRange(50, 100);
            int total = 0;
            for (int i = 50; i <= 100; i++) {
                Console.WriteLine("{0}:\t{1}", i, winners[i][i - 1]);
                total += winners[i][i - 1];
            }
            Console.WriteLine("\t{0}", total);
        }

        static IDictionary<int, int[]> ComputeRulerRange(int min, int max) {
            var best = new Dictionary<int, int[]>();

            var naive = Naive(max);
            for (int i = min; i <= max; i++) best[i] = naive.Take(i).ToArray();

            var finiteFields = FiniteFields(max * 11 / 10).OrderBy(x => x.Size).ToArray();

            // The projective plane method generates rulers of length p^a + 1 for prime powers p^a.
            // We can then look at subrulers for a reasonable range, say down to two prime powers below.
            for (int ppi = 0; ppi < finiteFields.Length; ppi++) {
                // Range under consideration
                var field = finiteFields[ppi];
                int q = field.Size;
                int subFrom = Math.Max(min, ppi >= 2 ? finiteFields[ppi - 2].Size : 1);
                int subTo = Math.Min(max, q + 1);
                if (subTo < subFrom) continue;

                int m = q * q + q + 1;
                foreach (var ruler in ProjectiveRulers(field)) {
                    for (int sub = subFrom; sub <= subTo; sub++) {
                        var subruler = BestSubruler(ruler, sub, m);
                        if (subruler[sub - 1] < best[sub][sub - 1]) best[sub] = subruler;
                    }
                }
            }

            // Similarly for the affine plane method, which generates rulers of length p^a for prime powers p^a
            for (int ppi = 0; ppi < finiteFields.Length; ppi++) {
                // Range under consideration
                var field = finiteFields[ppi];
                int q = field.Size;
                int subFrom = Math.Max(min, ppi >= 2 ? finiteFields[ppi - 2].Size : 1);
                int subTo = Math.Min(max, q);
                if (subTo < subFrom) continue;

                int m = q * q - 1;
                foreach (var ruler in AffineRulers(field)) {
                    for (int sub = subFrom; sub <= subTo; sub++) {
                        var subruler = BestSubruler(ruler, sub, m);
                        if (subruler[sub - 1] < best[sub][sub - 1]) best[sub] = subruler;
                    }
                }
            }

            return best;
        }

        static int[] BestSubruler(int[] ruler, int sub, int m) {
            int[] expand = new int[ruler.Length + sub - 1];
            for (int i = 0; i < ruler.Length; i++) expand[i] = ruler[i];
            for (int i = 0; i < sub - 1; i++) expand[ruler.Length + i] = ruler[i] + m;

            int best = m, bestIdx = -1;
            for (int i = 0; i < ruler.Length; i++) {
                if (expand[i + sub - 1] - expand[i] < best) {
                    best = expand[i + sub - 1] - expand[i];
                    bestIdx = i;
                }
            }

            return expand.Skip(bestIdx).Take(sub).Select(x => x - ruler[bestIdx]).ToArray();
        }

        static IEnumerable<int[]> ProjectiveRulers(FiniteField field) {
            var q = field.Size;
            var fq3 = PowerField.Create(field, 3);
            var m = q * q + q + 1;
            var g = fq3.Generators.First();

            // Define the set T<k> = {0} \union {a \in [q^3-1] : g^a - kg \in F(q)} for 0 != k \in F(q)
            // This could alternatively be T<k> = {0} \union {log_g(b - kg) : b in F(q)} for 0 != k \in F(q)
            // Then T<k> % (q^2 + q + 1) gives a Golomb ruler.
            // For a given generator we seem to get the same ruler for every k.
            var t_k = new HashSet<int>();
            t_k.Add(0);
            var ga = fq3.One;
            for (int a = 1; a < fq3.Size; a++) {
                ga = ga * g;
                if (fq3.Convert(ga + g) < q) t_k.Add(a % m);
            }

            // TODO: optimise by detecting duplicates
            for (int s = 1; s < m; s++) {
                if (Gcd(s, m) == 1) yield return t_k.Select(x => x * s % m).OrderBy(x => x).ToArray();
            }
        }

        static IEnumerable<int[]> AffineRulers(FiniteField field) {
            var q = field.Size;
            var fq2 = PowerField.Create(field, 2);
            var m = q * q - 1;
            var g = fq2.Generators.First();

            // Define the set T<k> = {0} \union {a \in [q^2-1] : g^a - kg \in F(q)} for 0 != k \in F(q)
            // Then T<k> % (q^2 - 1) gives a Golomb ruler.
            var t_k = new HashSet<int>();
            var ga = fq2.One;
            for (int a = 1; a < fq2.Size; a++) {
                ga = ga * g;
                if (fq2.Convert(ga + g) < q) t_k.Add(a % m);
            }

            // TODO: optimise by detecting duplicates
            for (int s = 1; s < m; s++) {
                if (Gcd(s, m) == 1) yield return t_k.Select(x => x * s % m).OrderBy(x => x).ToArray();
            }
        }

        static int Gcd(int a, int b) {
            while (a != 0) {
                var t = b % a;
                b = a;
                a = t;
            }

            return b;
        }

        static int[] Naive(int size) {
            if (size == 0) return new int[0];
            if (size == 1) return new int[] { 0 };

            int[] ruler = new int[size];
            var diffs = new HashSet<int>();
            int i = 1, c = 1;
            while (true) {
                bool valid = true;
                for (int j = 0; j < i; j++) {
                    if (diffs.Contains(c - ruler[j])) { valid = false; break; }
                }

                if (valid) {
                    for (int j = 0; j < i; j++) diffs.Add(c - ruler[j]);
                    ruler[i++] = c;
                    if (i == size) return ruler;
                }

                c++;
            }
        }

        static IEnumerable<FiniteField> FiniteFields(int max) {
            bool[] isComposite = new bool[max + 1];
            for (int p = 2; p < isComposite.Length; p++) {
                if (!isComposite[p]) {
                     FiniteField baseField = new PrimeField(p); yield return baseField;
                    for (int pp = p * p, pow = 2; pp < max; pp *= p, pow++) yield return PowerField.Create(baseField, pow);
                    for (int pq = p * p; pq <= max; pq += p) isComposite[pq] = true;
                }
            }
        }
    }

    public abstract class FiniteField {
        private Lazy<FiniteFieldElement> _Zero;
        private Lazy<FiniteFieldElement> _One;

        public FiniteFieldElement Zero { get { return _Zero.Value; } }
        public FiniteFieldElement One { get { return _One.Value; } }
        public IEnumerable<FiniteFieldElement> Generators {
            get {
                for (int _g = 1; _g < Size; _g++) {
                    int pow = 0;
                    FiniteFieldElement g = Convert(_g), gpow = One;
                    while (true) {
                        pow++;
                        gpow = gpow * g;
                        if (gpow == One) break;
                        if (pow > Size) {
                            throw new Exception("Is this really a field? " + this);
                        }
                    }
                    if (pow == Size - 1) yield return g;
                }
            }
        }

        public abstract int Size { get; }
        internal abstract FiniteFieldElement Convert(int i);
        internal abstract int Convert(FiniteFieldElement f);

        internal abstract bool Eq(FiniteFieldElement a, FiniteFieldElement b);
        internal abstract FiniteFieldElement Negate(FiniteFieldElement a);
        internal abstract FiniteFieldElement Add(FiniteFieldElement a, FiniteFieldElement b);
        internal abstract FiniteFieldElement Mul(FiniteFieldElement a, FiniteFieldElement b);

        protected FiniteField() {
            _Zero = new Lazy<FiniteFieldElement>(() => Convert(0));
            _One = new Lazy<FiniteFieldElement>(() => Convert(1));
        }
    }

    public abstract class FiniteFieldElement {
        internal abstract FiniteField Field { get; }

        public static FiniteFieldElement operator -(FiniteFieldElement a) {
            return a.Field.Negate(a);
        }

        public static FiniteFieldElement operator +(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != b.Field) throw new ArgumentOutOfRangeException("b");
            return a.Field.Add(a, b);
        }

        public static FiniteFieldElement operator *(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != b.Field) throw new ArgumentOutOfRangeException("b");
            return a.Field.Mul(a, b);
        }

        public static bool operator ==(FiniteFieldElement a, FiniteFieldElement b) {
            if (Equals(a, null)) return Equals(b, null);
            else if (Equals(b, null)) return false;

            if (a.Field != b.Field) throw new ArgumentOutOfRangeException("b");
            return a.Field.Eq(a, b);
        }

        public static bool operator !=(FiniteFieldElement a, FiniteFieldElement b) { return !(a == b); }

        public override bool Equals(object obj) {
            return (obj is FiniteFieldElement) && (obj as FiniteFieldElement).Field == Field && this == (obj as FiniteFieldElement);
        }

        public override int GetHashCode() { return Field.Convert(this).GetHashCode(); }

        public override string ToString() { return Field.Convert(this).ToString(); }
    }

    public class PrimeField : FiniteField {
        private readonly int _Prime;
        private readonly PrimeFieldElement[] _Featherweight;

        internal int Prime { get { return _Prime; } }
        public override int Size { get { return _Prime; } }

        public PrimeField(int prime) {
            if (prime < 2) throw new ArgumentOutOfRangeException("prime");

            // TODO A primality test would be nice...

            _Prime = prime;
            _Featherweight = new PrimeFieldElement[Math.Min(prime, 256)];
        }

        internal override FiniteFieldElement Convert(int i) {
            if (i < 0 || i >= _Prime) throw new ArgumentOutOfRangeException("i");
            if (i >= _Featherweight.Length) return new PrimeFieldElement(this, i);
            if (Equals(_Featherweight[i], null)) _Featherweight[i] = new PrimeFieldElement(this, i);
            return _Featherweight[i];
        }

        internal override int Convert(FiniteFieldElement f) {
            if (f == null) throw new ArgumentNullException("f");
            if (f.Field != this) throw new ArgumentOutOfRangeException("f");

            return (f as PrimeFieldElement).Value;
        }

        internal override bool Eq(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            return (a as PrimeFieldElement).Value == (b as PrimeFieldElement).Value;
        }

        internal override FiniteFieldElement Negate(FiniteFieldElement a) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            var fa = a as PrimeFieldElement;
            return fa.Value == 0 ? fa : Convert(_Prime - fa.Value);
        }

        internal override FiniteFieldElement Add(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            return Convert(((a as PrimeFieldElement).Value + (b as PrimeFieldElement).Value) % _Prime);
        }

        internal override FiniteFieldElement Mul(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            return Convert(((a as PrimeFieldElement).Value * (b as PrimeFieldElement).Value) % _Prime);
        }

        public override string ToString() { return string.Format("F({0})", _Prime); }
    }

    internal class PrimeFieldElement : FiniteFieldElement {
        private readonly PrimeField _Field;
        private readonly int _Value;

        internal override FiniteField Field { get { return _Field; } }
        internal int Value { get { return _Value; } }

        internal PrimeFieldElement(PrimeField field, int val) {
            if (field == null) throw new ArgumentNullException("field");
            if (val < 0 || val >= field.Prime) throw new ArgumentOutOfRangeException("val");

            _Field = field;
            _Value = val;
        }
    }

    public class PowerField : FiniteField {
        private readonly FiniteField _BaseField;
        private readonly FiniteFieldElement[] _Polynomial;

        internal FiniteField BaseField { get { return _BaseField; } }
        internal int Power { get { return _Polynomial.Length; } }
        public override int Size { get { return (int)Math.Pow(_BaseField.Size, Power); } }

        public PowerField(FiniteField baseField, FiniteFieldElement[] polynomial) {
            if (baseField == null) throw new ArgumentNullException("baseField");
            if (polynomial == null) throw new ArgumentNullException("polynomial");
            if (polynomial.Length < 2) throw new ArgumentOutOfRangeException("polynomial");
            for (int i = 0; i < polynomial.Length; i++) if (polynomial[i].Field != baseField) throw new ArgumentOutOfRangeException("polynomial[" + i + "]");

            // TODO Check that the polynomial is irreducible over the base field.

            _BaseField = baseField;
            _Polynomial = polynomial.ToArray();
        }

        internal override FiniteFieldElement Convert(int i) {
            if (i < 0 || i >= Size) throw new ArgumentOutOfRangeException("i");

            var vec = new FiniteFieldElement[Power];
            for (int j = 0; j < vec.Length; j++) {
                vec[j] = BaseField.Convert(i % BaseField.Size);
                i /= BaseField.Size;
            }

            return new PowerFieldElement(this, vec);
        }

        internal override int Convert(FiniteFieldElement f) {
            if (f == null) throw new ArgumentNullException("f");
            if (f.Field != this) throw new ArgumentOutOfRangeException("f");

            var pf = f as PowerFieldElement;
            int i = 0;
            for (int j = Power - 1; j >= 0; j--) i = i * BaseField.Size + BaseField.Convert(pf.Value[j]);
            return i;
        }

        internal override bool Eq(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            var fa = a as PowerFieldElement;
            var fb = b as PowerFieldElement;
            for (int i = 0; i < Power; i++) if (fa.Value[i] != fb.Value[i]) return false;
            return true;
        }

        internal override FiniteFieldElement Negate(FiniteFieldElement a) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            return new PowerFieldElement(this, (a as PowerFieldElement).Value.Select(x => -x).ToArray());
        }

        internal override FiniteFieldElement Add(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            var fa = a as PowerFieldElement;
            var fb = b as PowerFieldElement;
            var vec = new FiniteFieldElement[Power];
            for (int i = 0; i < Power; i++) vec[i] = fa.Value[i] + fb.Value[i];
            return new PowerFieldElement(this, vec);
        }

        internal override FiniteFieldElement Mul(FiniteFieldElement a, FiniteFieldElement b) {
            if (a.Field != this) throw new ArgumentOutOfRangeException("a");
            if (b.Field != this) throw new ArgumentOutOfRangeException("b");

            var fa = a as PowerFieldElement;
            var fb = b as PowerFieldElement;

            // We consider fa and fb as polynomials of a variable x and multiply modulo (x^Power - _Polynomial).
            // But to keep things simple we want to manage the cascading modulo.
            var vec = Enumerable.Repeat(BaseField.Zero, Power).ToArray();
            var fa_xi = fa.Value.ToArray();
            for (int i = 0; i < Power; i++) {
                for (int j = 0; j < Power; j++) vec[j] += fb.Value[i] * fa_xi[j];
                if (i < Power - 1) ShiftLeft(fa_xi);
            }

            return new PowerFieldElement(this, vec);
        }

        private void ShiftLeft(FiniteFieldElement[] vec) {
            FiniteFieldElement head = vec[vec.Length - 1];
            for (int i = vec.Length - 1; i > 0; i--) vec[i] = vec[i - 1] + head * _Polynomial[i];
            vec[0] = head * _Polynomial[0];
        }

        public static FiniteField Create(FiniteField baseField, int power) {
            if (baseField == null) throw new ArgumentNullException("baseField");
            if (power < 2) throw new ArgumentOutOfRangeException("power");

            // Since the field is cyclic, there is only one finite field of a given prime power order (up to isomorphism).
            // For most practical purposes that means that we can pick any arbitrary monic irreducible polynomial.
            // We can abuse PowerField to do polynomial multiplication in the base field.
            var fakeField = new PowerField(baseField, Enumerable.Repeat(baseField.Zero, power).ToArray());
            var excluded = new HashSet<FiniteFieldElement>();
            for (int lpow = 1; lpow <= power / 2; lpow++) {
                int upow = power - lpow;
                // Consider all products of a monic polynomial of order lpow with a monic polynomial of order upow.
                int xl = (int)Math.Pow(baseField.Size, lpow);
                int xu = (int)Math.Pow(baseField.Size, upow);
                for (int i = xl; i < 2 * xl; i++) {
                    var pi = fakeField.Convert(i);
                    for (int j = xu; j < 2 * xu; j++) {
                        var pj = fakeField.Convert(j);
                        excluded.Add(-(pi * pj));
                    }
                }
            }

            for (int p = baseField.Size; true; p++) {
                var pp = fakeField.Convert(p) as PowerFieldElement;
                if (!excluded.Contains(pp)) return new PowerField(baseField, pp.Value.ToArray());
            }
        }

        public override string ToString() {
            var sb = new System.Text.StringBuilder();
            sb.AppendFormat("GF({0}) with primitive polynomial x^{1} ", Size, Power);
            for (int i = Power - 1; i >= 0; i--) sb.AppendFormat("+ {0}x^{1}", _Polynomial[i], i);
            sb.AppendFormat(" over base field ");
            sb.Append(_BaseField);
            return sb.ToString();
        }
    }

    internal class PowerFieldElement : FiniteFieldElement {
        private readonly PowerField _Field;
        private readonly FiniteFieldElement[] _Vector; // The version of Mono I have doesn't include IReadOnlyList<T>

        internal override FiniteField Field { get { return _Field; } }
        internal FiniteFieldElement[] Value { get { return _Vector; } }

        internal PowerFieldElement(PowerField field, params FiniteFieldElement[] vector) {
            if (field == null) throw new ArgumentNullException("field");
            if (vector == null) throw new ArgumentNullException("vector");
            if (vector.Length != field.Power) throw new ArgumentOutOfRangeException("vector");
            for (int i = 0; i < vector.Length; i++) if (vector[i].Field != field.BaseField) throw new ArgumentOutOfRangeException("vector[" + i + "]");

            _Field = field;
            _Vector = vector.ToArray();
        }
    }
}

結果

残念ながら、ルーラーを追加すると、投稿サイズの制限を超えて約15,000文字かかるため、pastebinにあります。


[50、100]のルーラーをどこかに投稿してくれませんか?試してみたい遺伝的アルゴリズムがあり、シード値を与えます。
orlp

@orlp、リンクを追加しました。
ピーターテイラー

2
私が疑ったように、進化的アルゴリズムはこれらの優れた標本から何も役に立たない。最初は進化アルゴリズムが機能するように見えましたが(無効なルーラーから実際のルーラーに即座に移動します)、進化アルゴリズムが機能するにはグローバル構造が多すぎます。
orlp

5

Python 3、スコア603001/734078 = 0.82144

Erdős–Turan構成と組み合わせた単純な検索:

2pk+k2モッドpk[0p1]

奇数の素数pに対して、これは漸近的に最適なゴロム定規を与えます。

def isprime(n):
    if n < 2: return False
    if n % 2 == 0: return n == 2
    k = 3
    while k*k <= n:
         if n % k == 0: return False
         k += 2
    return True

rulers = []
ruler = []
d = set()
n = 0
while len(ruler) <= 100:
    order = len(ruler) + 1
    if order > 2 and isprime(order):
        ruler = [2*order*k + k*k%order for k in range(order)]
        d = {a-b for a in ruler for b in ruler if a > b}
        n = max(ruler) + 1
        rulers.append(tuple(ruler))
        continue

    nd = set(n-e for e in ruler)
    if not d & nd:
        ruler.append(n)
        d |= nd
        rulers.append(tuple(ruler))
    n += 1


isuniq = lambda l: len(l) == len(set(l))
isruler = lambda l: isuniq([a-b for a in l for b in l if a > b])

assert all(isruler(r) for r in rulers)

rulers = list(sorted([r for r in rulers if 50 <= len(r) <= 100], key=len))
print(sum(max(r) for r in rulers))

それはオーダーのゴロム定規得られます。私は、この構造は漸近的に最適であるとは思わないpし、約長さを2p^2ゴロムための支配者が存在するのに対し、n約や長さをn^2漸近。
グレッグマーティン

@GregMartin漸近的には差がない2p^2p^2
orlp

「漸近的に」の定義に依存しますが、私にとっては、この文脈では非常に異なっています。
グレッグマーティン

3

Mathematica、スコア276235/734078 <0.376302

ruzsa[p_, i_] := Module[{g = PrimitiveRoot[p]},
  Table[ChineseRemainder[{t, i PowerMod[g, t, p]}, {p - 1, p}], {t, 1, p - 1}] ]

reducedResidues[m_] := Select[Range@m, CoprimeQ[m, #] &]

rotate[set_, m_] := Mod[set - #, m] & /@ set

scaledRuzsa[p_] := Union @@ Table[ Sort@Mod[a b, p (p - 1)],
  {a, reducedResidues[p (p - 1)]}, {b, rotate[ruzsa[p, 1], p (p - 1)]}]

manyRuzsaSets = Join @@ Table[scaledRuzsa[Prime[n]], {n, 32}];

tryGolomb[set_, k_] := If[Length[set] < k, Nothing, Take[set, k]]

Table[First@MinimalBy[tryGolomb[#, k] & /@ manyRuzsaSets, Max], {k, 50, 100}]

この関数ruzsaは、Imre Z. RuzsaにあるGolobmルーラー(Sidonセットとも呼ばれます)の構築を実装します。整数のセットで線形方程式を解きます。I.アクタARITH、65(3):259から282、1993。素数が与えられた場合p、この構造p-1は整数にモジュロを含む要素を持つゴロム定規を生成しますp(p-1)(整数自体がゴロム定規であるよりもさらに強い条件です)。

モジュロ整数で作業することのもう1つの利点はm、ゴロムルーラーを回転(すべての要素に同じ定数をモジュロで追加m)してスケーリングできることです(その定数がに素数である限り、すべての要素に同じ定数を掛けますm)。結果は依然としてゴロムの支配者です。場合によっては、最大の整数が大幅に減少します。したがって、関数scaledRuzsaはこれらすべてのスケーリングを試行し、結果を記録します。manyRuzsaSetsこの構築と最初の32個の素数すべてに対するスケーリングの結果が含まれます(少し自由に選択できますが、32番目の素数131は100よりも十分に大きいです)。このセットには約57,000人のGolomb定規があり、計算には数分かかります。

もちろん、kゴロム定規の最初の要素自体がゴロム定規を形成します。したがって、関数tryGolombは、上記で計算されたセットのいずれかから作成されたこのようなルーラーを調べます。最後の行はTable...からすべての注文のそれができる最善ゴロム定規を選択50する100すべてのゴロム定規は、このようにして求められたから、。

見つかった長さは次のとおりです。

{2241, 2325, 2399, 2578, 2640, 2762, 2833, 2961, 3071, 3151, 3194, 3480, 3533, 3612, 3775, 3917, 4038, 4150, 4237, 4368, 4481, 4563, 4729, 4974, 5111, 5155, 5297, 5504, 5583, 5707, 5839, 6077, 6229, 6480, 6611, 6672, 6913, 6946, 7025, 7694, 7757, 7812, 7969, 8139, 8346, 8407, 8678, 8693, 9028, 9215, 9336}

私はもともとこれを、シンガーとボーズの2つの他の構造と組み合わせようとしました。しかし、Peter Taylorの答えはすでにこれを実装しているようですので、おそらく私は単にそれらの長さを回復するでしょう。


私はmあなたが自由に回転/スケールできる整数を法として働くことであなたの主張に混乱しています。[0, 1, 4, 6]mod 7を見てください。1を追加すると、Golombのルーラー[0, 1, 2, 5]ではないが得られます。
-orlp

それは、mod-7 Golomb定規で作業を開始する必要があるためです。たとえば、7を法とする[0, 1, 4, 6]mod-7 Golombルーラーではありません。1 – 00 – 6
グレッグマーティン

1
C#での有限フィールド実装を作成およびデバッグしている間に、Mathematicaをより良く知ってほしいと思いました。間違いなく仕事にふさわしい言語の1つです。
ピーターテイラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.