Znajdź najkrótszych władców Golomb

15

Linijki Golomb są zestawami liczb całkowitych nieujemnych, tak że żadne dwie pary liczb całkowitych w zestawie nie są w tej samej odległości od siebie.

Na przykład [0, 1, 4, 6]jest linijką Golomb, ponieważ wszystkie odległości między dwiema liczbami całkowitymi w tym zestawie są unikalne:

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

Dla uproszczenia tego wyzwania (a ponieważ tłumaczenie jest trywialne), narzucamy, że linijka Golomba zawsze zawiera liczbę0 (co robi poprzedni przykład).

Ponieważ ten zestaw ma długość 4, mówimy, że jest to władca Golomb z rzędu 4 . Największa odległość w tym zestawie (lub elemencie, ponieważ 0zawsze jest w zestawie) 6, dlatego mówimy, że jest to władca Golombów o długości 6 .

Twoje zadanie

Znajdź Golomb władców kolejności 50 do 100(włącznie), które mają za małe długości , jak można znaleźć. Znalezione linijki nie muszą być optymalne (patrz poniżej).

Optymalność

NMówi się, że linijka Golomb jest optymalna, jeśli nie ma innej linijki Golomb No mniejszej długości.

Optymalni władcy Golomb są znani z rozkazów mniejszych niż 28 , chociaż znalezienie i udowodnienie optymalności jest coraz trudniejsze wraz ze wzrostem rozkazu.

Dlatego nie oczekuje się, że znajdziesz optymalną linijkę Golombów dla któregokolwiek z rozkazów pomiędzy 50i 100(a jeszcze mniej oczekuje się, że możesz udowodnić, że są optymalne).

Nie ma ograniczeń czasowych w wykonywaniu programu.

Linia bazowa

Poniższa lista to lista długości władców Golomb od 50do 100(w kolejności) ocenianych za pomocą naiwnej strategii wyszukiwania (dzięki @PeterTaylor za tę listę):

[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]

Suma wszystkich tych długości wynosi 734078.

Punktacja

Twój wynik będzie suma długości wszystkich władców Golomb między 50i 100, podzielonej przez sumę długości władców Golomb pomiędzy 50i 100na początku badania: 734078.

W przypadku, gdy nie znalazłeś linijki Golomb dla konkretnego zamówienia, obliczasz swój wynik w ten sam sposób, używając podwójnej długości w linii podstawowej dla tego konkretnego zamówienia.

Odpowiedź z najniższym wynikiem wygrywa.

W przypadku remisu porównuje się długości największego zamówienia, w którym obie odpowiedzi różnią się, i wygrywa najkrótsza. W przypadku, gdy obie odpowiedzi mają takie same długości dla wszystkich zamówień, wygrywa odpowiedź, która została wysłana jako pierwsza.

Fatalizować
źródło
2
Związane z. (To samo wyzwanie w 2D.)
Martin Ender
I wpis OEIS .
Martin Ender,
Kiedy mówisz o linijkach od 50 do 100, masz na myśli zakres [50, 100)? Więc nie licząc linijki rzędu 100? Ponieważ linia bazowa zawiera tylko 50 elementów.
orlp
1
Dygresja: najmniejsza możliwa długość linijki Golomb porządku njest n(n-1)/2, ponieważ to jak wiele pozytywnych różnice istnieją. Dlatego najmniejszy możliwy wynik w tym wyzwaniu to 147050/734078 > 0.2003193.
Greg Martin
2
@GregMartin Dzięki, choć nie jest to „najmniejszy możliwy wynik”, ale raczej dolna granica tego najmniejszego możliwego wyniku!
Fatalize

Odpowiedzi:

8

C #, 259421/734078 ~ = 0,3534

Metody

W końcu znalazłem mniej lub bardziej czytelne wyjaśnienie metody pola rzutowego (metoda Singera) w Konstrukcjach uogólnionych zestawów sidonowych , chociaż nadal uważam, że można ją nieco poprawić. Okazuje się, że jest bardziej podobna do metody pola afinicznego (metoda Bosego) niż inne artykuły, które czytałem.

Zakłada to znajomość skończonych pól . Rozważmy, że jest siłą pierwszą i niech F ( q ) będzie naszym polem bazowym.q=paF(q)

Metoda pola afinicznego działa na . Wziąć generator g 2 o F ( Q 2 ) , a nie od zera elementów K o F ( q ) i za zestaw { : g 2F(q2)g2F(q2)kF(q) Wartości te tworzą modułową modulę Golomb mod q 2 - 1 . Dalsze linijki można uzyskać, mnożącmoduł q 2 - 1 przez dowolną liczbę, która jest koprime z modułem.

{a:g2akg2Fq}
q21q21

F(q3)g3F(q3)kF(q)

{0}{a:g3akg3Fq}
q2+q+1

Zauważ, że te metody między nimi dają najbardziej znane wartości dla każdej długości większej niż 16. Tomas Rokicki i Gil Dogon oferują nagrodę w wysokości 250 USD za każdego, kto pokonuje ich na długości od 36 do 40000. Dlatego każdy, kto pokonał tę odpowiedź, czeka na pieniądze nagroda.

Kod

C # nie jest bardzo idiomatyczny, ale potrzebuję go do skompilowania ze starą wersją Mono. Ponadto, pomimo sprawdzania argumentów, nie jest to kod jakości produkcji. Nie jestem zadowolony z typów, ale nie sądzę, że istnieje naprawdę dobre rozwiązanie w C #. Może w F # lub C ++ z szalonym szablonem.

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();
        }
    }
}

Wyniki

Niestety dodanie linijek zabrałoby mi około 15 000 znaków powyżej limitu rozmiaru postu, więc są one na pastebinie .

Peter Taylor
źródło
Czy byłbyś tak miły, gdybyś wysłał gdzieś swoich władców na [50, 100]? Mam algorytm genetyczny, który chcę wypróbować, karmiąc go pewnymi wartościami nasion.
orlp
@orlp, dodał link.
Peter Taylor
2
Jak podejrzewałem, algorytm ewolucyjny nie może wydobyć nic użytecznego z tych doskonałych okazów. Chociaż początkowo wydawało się, że algorytmy ewolucyjne mogą działać (prawie natychmiast przenosi się z nieprawidłowych linijek do rzeczywistych linijek), istnieje zbyt duża globalna struktura, aby algorytm ewolucyjny mógł działać.
orlp
5

Python 3, wynik 603001/734078 = 0,82144

Naiwne wyszukiwanie w połączeniu z konstrukcją Erdős – Turan:

2pk+(k2modp),k[0,p1]

Dla nieparzystych liczb pierwszych p daje to asymptotycznie optymalną linijkę golomb.

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))
orlp
źródło
Nie sądzę, że ta konstrukcja jest asymptotycznie optymalna: daje linijkę Golomb w porządku pi długości 2p^2, podczas gdy istnieją linijki Golomb w nprzybliżeniu i długościn^2 asymptotycznie.
Greg Martin
@GregMartin Asymptotycznie nie ma różnicy między 2p^2i p^2.
orlp
Chyba zależy od twojej definicji „asymptotycznie”, ale dla mnie w tym kontekście są one bardzo różne.
Greg Martin
3

Mathematica, wynik 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}]

Ta funkcja ruzsaimplementuje konstrukcję linijki Golobma (zwanej także zestawem Sidonów ) znalezionej w Imre Z. Ruzsa. Rozwiązywanie równania liniowego w zbiorze liczb całkowitych. I. Acta Arith., 65 (3): 259–282, 1993 . Biorąc pod uwagę liczbę pierwszą p, ta konstrukcja daje linijkę Golomb z p-1elementami zawartymi w module liczb całkowitych p(p-1)(jest to nawet silniejszy warunek niż bycie władcą Golomb w samych liczbach całkowitych).

Kolejną zaletą pracy w module liczb całkowitych mjest to, że dowolną linijkę Golomba można obracać (ta sama stała dodawana do wszystkich elementów modulo m) i skalować (wszystkie elementy pomnożone przez tę samą stałą, o ile ta stała jest względnie pierwsza m), i wynikiem jest nadal władca Golomb; czasami największa liczba całkowita jest znacznie zmniejszana. Dlatego funkcja scaledRuzsawypróbowuje wszystkie te skalowania i rejestruje wyniki. manyRuzsaSetszawiera wyniki wykonania tej konstrukcji i skalowania dla wszystkich pierwszych 32 liczb pierwszych (wybranych nieco arbitralnie, ale 32 liczba pierwsza, 131, jest znacznie większa niż 100); w tym zestawie znajduje się prawie 57 000 władców Golombów, których obliczenie zajmuje kilka minut.

Oczywiście pierwsze kelementy samego władcy Golombów tworzą władcę Golombów. Tak więc funkcja tryGolombpatrzy na taką linijkę wykonaną z dowolnego zestawu obliczonego powyżej. Ostatnia linia Table...wybiera najlepszego władcę Golomb, jaki może, w dowolnej kolejności od 50do 100, spośród wszystkich władców Golomb znalezionych w ten sposób.

Znalezione długości to:

{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}

Pierwotnie zamierzałem połączyć to z dwiema innymi konstrukcjami, Singer i Bose; ale wydaje się, że Petera Taylora już to zaimplementowała, więc prawdopodobnie po prostu odzyskałbym te długości.

Greg Martin
źródło
Jestem zdezorientowany twoim twierdzeniem, że pracując w module liczb całkowitych mmożesz dowolnie obracać / skalować. Spójrz na [0, 1, 4, 6]mod 7. Jeśli dodam 1, otrzymamy [0, 1, 2, 5], który nie jest władcą Golombów.
orlp
To dlatego, że musisz zacząć od linijki Golomb mod-7, aby zadziałała. [0, 1, 4, 6]nie jest linijką Golomb mod-7, ponieważ na przykład 1 – 0równa się 0 – 6modulo 7.
Greg Martin
1
Podczas pisania i debugowania mojej implementacji pola skończonego w języku C # żałowałem, że nie znam Mathematiki lepiej. Zdecydowanie jeden z odpowiednich języków do pracy.
Peter Taylor