Trouver des partitions sans somme


17

Résumé

Compte tenu de l' entrée k, trouver une partition d'entiers 1à nen ksous - ensembles sans somme pour le plus grand npossible dans les 10 minutes.

Contexte: numéros Schur

Un ensemble Aest sans somme si son auto-somme A + A = { x + y | x, y in A}n'a aucun élément en commun avec lui.

Pour chaque entier positif, kil y a un plus grand entier S(k)tel que l'ensemble {1, 2, ..., S(k)}peut être partitionné en ksous-ensembles sans somme. Ce numéro est appelé le k ème numéro Schur (OEIS A045652 ).

Par exemple S(2) = 4,. Nous pouvons partitionner en {1, 2, 3, 4}tant que {1, 4}, {2, 3}, et c'est la partition unique en deux sous-ensembles sans somme, mais nous ne pouvons pas maintenant ajouter un 5à l' une ou l'autre partie.

Défi

Écrivez un programme déterministe qui fait ce qui suit:

  • Prendre un entier positif ken entrée
  • Ecrire l'horodatage Unix actuel sur stdout
  • Génère une séquence de partitions de 1à nen ksous-ensembles sans somme à augmenter n, en suivant chaque séquence avec l'horodatage Unix actuel.

Le gagnant sera le programme qui imprime une partition pour la plus grande ndans les 10 minutes sur mon ordinateur lorsqu'il est saisi 5. Les liens seront rompus par le temps le plus rapide pour trouver une partition pour le plus grand n, en moyenne sur trois exécutions: c'est pourquoi la sortie devrait inclure des horodatages.

Détails importants:

  • J'ai Ubuntu Precise, donc si votre langue n'est pas prise en charge, je ne pourrai pas la noter.
  • J'ai un processeur Intel Core2 Quad, donc si vous voulez utiliser le multithreading, il est inutile d'utiliser plus de 4 threads.
  • Si vous souhaitez que j'utilise des indicateurs ou une implémentation de compilateur particuliers, documentez-le clairement dans votre réponse.
  • Vous ne devez pas casse spéciale votre code pour gérer l'entrée 5.
  • Vous n'êtes pas obligé de générer chaque amélioration trouvée. Par exemple, pour l'entrée, 2vous ne pouvez générer que la partition n = 4. Cependant, si vous ne produisez rien dans les 10 premières minutes, je noterai cela n = 0.

Réponses:


8

Python 3, tri par plus grand nombre, n = 92 121

Merci à Martin Büttner pour une suggestion qui a amélioré de manière inattendue le maximum natteint.

Dernière sortie:

[2, 3, 11, 12, 29, 30, 38, 39, 83, 84, 92, 93, 110, 111, 119, 120]
[1, 4, 10, 13, 28, 31, 37, 40, 82, 85, 91, 94, 109, 112, 118, 121]
[5, 6, 7, 8, 9, 32, 33, 34, 35, 36, 86, 87, 88, 89, 90, 113, 114, 115, 116, 117]
[14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108]
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81]

L'algorithme est le même que ma réponse précédente, citée ci-dessous:

Il y a k bacs qui contiennent à la fois les chiffres et ceux qui ne peuvent plus y entrer. À chaque profondeur de l'itération (c'est fondamentalement une recherche en profondeur d'abord), l'ordre des cases est mélangé et le numéro suivant (nextN) est (séquentiellement) placé dans les cases qui peuvent le prendre, puis va plus loin. S'il n'y en a pas, il revient, sauvegardant une étape.

... à une exception près: la commande de bac n'est pas mélangée. Au lieu de cela, il est trié de telle manière que les bacs avec le plus grand nombre viennent en premier. Cela a atteint n = 121en 8 secondes!

Code:

from copy import deepcopy
from random import shuffle, seed
from time import clock, time
global maxN
maxN = 0
clock()

def search(k,nextN=1,sets=None):
    global maxN
    if clock() > 600: return

    if nextN == 1: #first iteration
        sets = []
        for i in range(k):
            sets.append([[],[]])

    sets.sort(key=lambda x:max(x[0]or[0]), reverse=True)
    for i in range(k):
        if clock() > 600: return
        if nextN not in sets[i][1]:
            sets2 = deepcopy(sets)
            sets2[i][0].append(nextN)
            sets2[i][1].extend([nextN+j for j in sets2[i][0]])
            nextN2 = nextN + 1

            if nextN > maxN:
                maxN = nextN
                print("New maximum!",maxN)
                for s in sets2: print(s[0])
                print(time())
                print()

            search(k, nextN2, sets2)

search(5)

Remarque: le tri par le plus grand nombre de nombres autorisés dans la plage des nombres interdits donne n=59et le tri par le plus grand nombre de nombres autorisés moins que le nombre nextNdonné n=64. Le tri selon la longueur de la liste des numéros non autorisés (qui peut avoir des répétitions) conduit très rapidement à un n=30motif élégant .
El'endia Starman

Le format de l'heure de sortie n'est pas correct (devrait être en secondes depuis l'époque, mais je vois Tue Nov 10 00:44:25 2015), mais j'ai vu n=92en moins de 2 secondes.
Peter Taylor

Ah, je pensais que le format de l'heure n'était pas aussi important que de montrer exactement combien de temps cela prenait. Je vais le comprendre et le changer cependant. EDIT: D'oh. Je pris ctimesur timeparce que la sortie était plus jolie quand timeétait exactement ce que j'aurais pris.
El'endia Starman

Vous savez, vous pouvez également trier par le plus grand nombre dans le bac, car le plus grand nombre interdit sera toujours le double.
Martin Ender

@ MartinBüttner: ...... Je ... euh ... Je n'ai aucune idée de comment ou pourquoi, mais ça devient n=121. oO
El'endia Starman

7

Python 3, 121, <0,001 s

Grâce à l'heuristique améliorée grâce à Martin Buttner, nous n'avons même pas besoin d'aléatoire.

Production:

1447152500.9339304
[1, 4, 10, 13, 28, 31, 37, 40, 82, 85, 91, 94, 109, 112, 118, 121]
[2, 3, 11, 12, 29, 30, 38, 39, 83, 84, 92, 93, 110, 111, 119, 120]
[5, 6, 7, 8, 9, 32, 33, 34, 35, 36, 86, 87, 88, 89, 90, 113, 114, 115, 116, 117]
[14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108]
[41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81]
1447152500.934646 121

Code:

from copy import deepcopy
from random import seed, randrange
from time import clock, time
from cProfile import run

n = 5

seed(0)

def heuristic(bucket):
    return len(bucket[0]) and bucket[0][-1]

def search():
    best = 0
    next_add = 1
    old_add = 0
    lists = [[[],set()] for _ in range(n)]
    print(time())
    while clock() < 600 and next_add != old_add:
        old_add = next_add
        lists.sort(key=heuristic, reverse=True)
        for i in range(n):
            if next_add not in lists[i][1]:
                lists[i][0].append(next_add)
                lists[i][1].update([next_add + old for old in lists[i][0]])
                if next_add > best:
                    best = next_add
                next_add += 1
                break

    for l in lists:
        print(l[0])
    print(time(), next_add-1, end='\n\n')

search()

Python 3, 112

Trier par somme des 2 premiers éléments + biais

[40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79]
[7, 8, 9, 10, 11, 12, 13, 27, 28, 29, 30, 31, 32, 33, 80, 81, 82, 83, 84, 85, 86, 100, 101, 102, 103, 104, 105, 106]
[3, 4, 14, 19, 21, 26, 36, 37, 87, 92, 94, 99, 109, 110]
[2, 5, 16, 17, 20, 23, 24, 35, 38, 89, 90, 96, 97, 108, 111]
[1, 6, 15, 18, 22, 25, 34, 39, 88, 91, 93, 95, 98, 107, 112]
1447137688.032085 138.917074 112

J'ai copié la structure de données d'El'endia Starman, qui se compose d'une liste de paires, où le premier élément de la paire est les éléments de ce compartiment et le second les sommes de ce compartiment.

Je commence par la même approche «suivre les sommes disponibles». Mon heuristique de tri est simplement la somme des deux plus petits éléments d'une liste donnée. J'ajoute également un petit biais aléatoire pour essayer différentes possibilités.

Chaque itération place simplement chacun le nouveau numéro dans la première poubelle avalible, semblable à un gourmand aléatoire. Une fois que cela échoue, il redémarre simplement.

from copy import deepcopy
from random import seed, randrange
from time import clock, time

n = 5

seed(0)

def skew():
    return randrange(9)

best = 0
next_add = old_add = 1
while clock() < 600:
    if next_add == old_add:
        lists = [[[],[]] for _ in range(n)]
        next_add = old_add = 1
    old_add = next_add
    lists.sort(key=lambda x:sum(x[0][:2]) + skew(), reverse=True)
    for i in range(n):
        if next_add not in lists[i][1]:
            lists[i][0].append(next_add)
            lists[i][1].extend([next_add + old for old in lists[i][0]])
            if next_add > best:
                best = next_add
                for l in lists:
                    print(l[0])
                print(time(), clock(), next_add, end='\n\n')
            next_add += 1
            break

Wow, cela ressemble extrêmement à mon code. : P;) (ça ne me dérange pas du tout.)
El'endia Starman

@ El'endiaStarman Credit ajouté. C'est une bonne base.
isaacg

7

Java 8, n = 142 144

Dernière sortie:

@ 0m 31s 0ms
n: 144
[9, 12, 17, 20, 22, 23, 28, 30, 33, 38, 41, 59, 62, 65, 67, 70, 72, 73, 75, 78, 80, 83, 86, 91, 107, 115, 117, 122, 123, 125, 128, 133, 136]
[3, 8, 15, 24, 25, 26, 31, 35, 45, 47, 54, 58, 64, 68, 81, 87, 98, 100, 110, 114, 119, 120, 121, 130, 137, 142]
[5, 13, 16, 19, 27, 36, 39, 42, 48, 50, 51, 94, 95, 97, 103, 106, 109, 112, 118, 126, 129, 132, 138, 140, 141]
[2, 6, 11, 14, 34, 37, 44, 53, 56, 61, 69, 76, 79, 84, 89, 92, 101, 104, 108, 111, 124, 131, 134, 139, 143, 144]
[1, 4, 7, 10, 18, 21, 29, 32, 40, 43, 46, 49, 52, 55, 57, 60, 63, 66, 71, 74, 77, 82, 85, 88, 90, 93, 96, 99, 102, 105, 113, 116, 127, 135]

Effectue une recherche aléatoire prédéfinie répartie sur 4 threads. Lorsqu'il ne parvient pas à trouver une partition pour y entrer, nil essaie de libérer de l'espace pour nune partition à la fois en en vidant le plus possible dans les autres partitions.

modifier: peaufiné l'algorithme pour libérer de l'espace pour n, également ajouté la possibilité de revenir à un choix précédent et de choisir à nouveau.

note: la sortie n'est pas strictement déterministe car il y a plusieurs threads impliqués et ils peuvent finir par mettre à jour le meilleur n trouvés jusqu'à présent dans un ordre brouillé; le score final de 144 est cependant déterministe et est atteint assez rapidement: 30 secondes sur mon ordinateur.

Le code est:

import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Deque;
import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

public class SumFree {

    private static int best;

    public static void main(String[] args) {
        int k = 5; // Integer.valueOf(args[0]);
        int numThreadsPeterTaylorCanHandle = 4;

        long start = System.currentTimeMillis();
        long end = start + TimeUnit.MINUTES.toMillis(10);

        System.out.println(start);

        Random rand = new Random("Lucky".hashCode());
        for (int i = 0; i < numThreadsPeterTaylorCanHandle; i++) {
            new Thread(() -> search(k, new Random(rand.nextLong()), start, end)).start();
        }
    }

    private static void search(int k, Random rand, long start, long end) {
        long now = System.currentTimeMillis();
        int localBest = 0;

        do {
            // create k empty partitions
            List<Partition> partitions = new ArrayList<>();
            for (int i = 0; i < k; i++) {
                partitions.add(new Partition());
            }

            Deque<Choice> pastChoices = new ArrayDeque<>();
            int bestNThisRun = 0;

            // try to fill up the partitions as much as we can
            for (int n = 1;; n++) {
                // list of partitions that can fit n
                List<Partition> partitionsForN = new ArrayList<>(k);
                for (Partition partition : partitions) {
                    if (!partition.sums.contains(n)) {
                        partitionsForN.add(partition);
                    }
                }

                // if we can't fit n anywhere then try to free up some space
                // by rearranging partitions
                Set<Set<Set<Integer>>> rearrangeAttempts = new HashSet<>();
                rearrange: while (partitionsForN.size() == 0 && rearrangeAttempts
                        .add(partitions.stream().map(Partition::getElements).collect(Collectors.toSet()))) {

                    Collections.shuffle(partitions, rand);
                    for (int candidateIndex = 0; candidateIndex < k; candidateIndex++) {
                        // partition we will try to free up
                        Partition candidate = partitions.get(candidateIndex);
                        // try to dump stuff that adds up to n into the other
                        // partitions
                        List<Integer> badElements = new ArrayList<>(candidate.elements.size());
                        for (int candidateElement : candidate.elements) {
                            if (candidate.elements.contains(n - candidateElement)) {
                                badElements.add(candidateElement);
                            }
                        }
                        for (int i = 0; i < k && !badElements.isEmpty(); i++) {
                            if (i == candidateIndex) {
                                continue;
                            }

                            Partition other = partitions.get(i);

                            for (int j = 0; j < badElements.size(); j++) {
                                int candidateElement = badElements.get(j);
                                if (!other.sums.contains(candidateElement)
                                        && !other.elements.contains(candidateElement + candidateElement)) {
                                    boolean canFit = true;
                                    for (int otherElement : other.elements) {
                                        if (other.elements.contains(candidateElement + otherElement)) {
                                            canFit = false;
                                            break;
                                        }
                                    }

                                    if (canFit) {
                                        other.elements.add(candidateElement);
                                        for (int otherElement : other.elements) {
                                            other.sums.add(candidateElement + otherElement);
                                        }
                                        candidate.elements.remove((Integer) candidateElement);
                                        badElements.remove(j--);
                                    }
                                }
                            }
                        }

                        // recompute the sums
                        candidate.sums.clear();
                        List<Integer> elementList = new ArrayList<>(candidate.elements);
                        int elementListSize = elementList.size();
                        for (int i = 0; i < elementListSize; i++) {
                            int ithElement = elementList.get(i);
                            for (int j = i; j < elementListSize; j++) {
                                int jthElement = elementList.get(j);
                                candidate.sums.add(ithElement + jthElement);
                            }
                        }

                        // if candidate can now fit n then we can go on
                        if (!candidate.sums.contains(n)) {
                            partitionsForN.add(candidate);
                            break rearrange;
                        }
                    }
                }

                // if we still can't fit in n, then go back in time to our last
                // choice (if it's saved) and this time choose differently
                if (partitionsForN.size() == 0 && !pastChoices.isEmpty() && bestNThisRun > localBest - localBest / 3) {
                    Choice lastChoice = pastChoices.peek();
                    partitions = new ArrayList<>(lastChoice.partitions.size());
                    for (Partition partition : lastChoice.partitions) {
                        partitions.add(new Partition(partition));
                    }
                    n = lastChoice.n;
                    Partition partition = lastChoice.unchosenPartitions
                            .get(rand.nextInt(lastChoice.unchosenPartitions.size()));
                    lastChoice.unchosenPartitions.remove(partition);
                    partition = partitions.get(lastChoice.partitions.indexOf(partition));
                    partition.elements.add(n);
                    for (int element : partition.elements) {
                        partition.sums.add(element + n);
                    }
                    if (lastChoice.unchosenPartitions.size() == 0) {
                        pastChoices.pop();
                    }
                    continue;
                }

                if (partitionsForN.size() > 0) {
                    // if we can fit in n somewhere,
                    // pick that somewhere randomly
                    Partition chosenPartition = partitionsForN.get(rand.nextInt(partitionsForN.size()));
                    // if we're making a choice then record it so that we may
                    // return to it later if we get stuck
                    if (partitionsForN.size() > 1) {
                        Choice choice = new Choice();
                        choice.n = n;
                        for (Partition partition : partitions) {
                            choice.partitions.add(new Partition(partition));
                        }
                        for (Partition partition : partitionsForN) {
                            if (partition != chosenPartition) {
                                choice.unchosenPartitions.add(choice.partitions.get(partitions.indexOf(partition)));
                            }
                        }
                        pastChoices.push(choice);

                        // only keep 3 choices around
                        if (pastChoices.size() > 3) {
                            pastChoices.removeLast();
                        }
                    }

                    chosenPartition.elements.add(n);
                    for (int element : chosenPartition.elements) {
                        chosenPartition.sums.add(element + n);
                    }
                    bestNThisRun = Math.max(bestNThisRun, n);
                }

                if (bestNThisRun > localBest) {
                    localBest = Math.max(localBest, bestNThisRun);

                    synchronized (SumFree.class) {
                        now = System.currentTimeMillis();

                        if (bestNThisRun > best) {
                            // sanity check
                            Set<Integer> allElements = new HashSet<>();
                            for (Partition partition : partitions) {
                                for (int e1 : partition.elements) {
                                    if (!allElements.add(e1)) {
                                        throw new RuntimeException("Oops!");
                                    }
                                    for (int e2 : partition.elements) {
                                        if (partition.elements.contains(e1 + e2)) {
                                            throw new RuntimeException("Oops!");
                                        }
                                    }
                                }
                            }
                            if (allElements.size() != bestNThisRun) {
                                throw new RuntimeException("Oops!" + allElements.size() + "!=" + bestNThisRun);
                            }

                            best = bestNThisRun;
                            System.out.printf("@ %dm %ds %dms\n", TimeUnit.MILLISECONDS.toMinutes(now - start),
                                    TimeUnit.MILLISECONDS.toSeconds(now - start) % 60, (now - start) % 1000);
                            System.out.printf("n: %d\n", bestNThisRun);
                            for (Partition partition : partitions) {
                                // print in sorted order since everyone else
                                // seems to to that
                                List<Integer> partitionElementsList = new ArrayList<>(partition.elements);
                                Collections.sort(partitionElementsList);
                                System.out.println(partitionElementsList);
                            }
                            System.out.printf("timestamp: %d\n", now);
                            System.out.println("------------------------------");
                        }
                    }
                }

                if (partitionsForN.size() == 0) {
                    break;
                }
            }
        } while (now < end);
    }

    // class representing a partition
    private static final class Partition {

        // the elements of this partition
        Set<Integer> elements = new HashSet<>();

        // the sums of the elements of this partition
        Set<Integer> sums = new HashSet<>();

        Partition() {
        }

        Partition(Partition toCopy) {
            elements.addAll(toCopy.elements);
            sums.addAll(toCopy.sums);
        }

        Set<Integer> getElements() {
            return elements;
        }
    }

    private static final class Choice {
        int n;
        List<Partition> partitions = new ArrayList<>();
        List<Partition> unchosenPartitions = new ArrayList<>();
    }
}

5

C, gourmand aléatoire, n = 91

Juste pour fournir une solution de base, cela se répète n, en gardant une trace des bacs et de leurs sommes et ajoute nà un bac aléatoire où il n'apparaît pas encore comme une somme. Il se termine une fois napparaît dans toutes les ksommes, et si le résultatn était meilleur que toute tentative précédente, l'imprime dans STDOUT.

L'entrée kest fournie via un argument de ligne de commande. Le maximum possible kest actuellement codé en dur à 10 car j'étais trop paresseux pour ajouter une allocation de mémoire dynamique, mais cela pourrait être corrigé facilement.

Je suppose que je pourrais aller à la recherche d'une meilleure graine maintenant, mais cette réponse n'est probablement pas particulièrement compétitive de toute façon, alors meh.

Voici la partition pour n = 91:

1 5 12 18 22 29 32 35 46 48 56 59 62 69 72 76 79 82 86 89
2 3 10 11 16 17 25 30 43 44 51 52 57 64 71 83 84 90 91
6 8 13 15 24 31 33 38 40 42 49 54 61 63 65 77 81 88
9 14 19 21 27 34 37 45 60 67 70 73 75 78 80 85
4 7 20 23 26 28 36 39 41 47 50 53 55 58 66 68 74 87

Et enfin, voici le code:

#include <stdlib.h>
#include <stdio.h>
#include <time.h>

#define MAX_K 10
#define MAX_N 1024

int main(int argc, char **argv) {
    if (argc < 2)
    {
        printf("Pass in k as a command-line argument");
        return 1;
    }

    printf("%u\n", (unsigned)time(NULL)); 

    int k = atoi(argv[1]);

    int sizes[MAX_K];
    int bins[MAX_K][MAX_N];
    int sums[MAX_K][2*MAX_N];
    int selection[MAX_K];
    int available_bins;

    int best = 0;

    srand(1447101176);

    while (1)
    {
        int i,j;
        for (i = 0; i < k; ++i)
            sizes[i] = 0;
        for (i = 0; i < k*MAX_N; ++i)
            bins[0][i] = 0;
        for (i = 0; i < k*MAX_N*2; ++i)
            sums[0][i] = 0;
        int n = 1;
        while (1)
        {
            available_bins = 0;
            for (i = 0; i < k; ++i)
                if (!sums[i][n])
                {
                    selection[available_bins] = i;
                    ++available_bins;
                }

            if (!available_bins) break;

            int bin = selection[rand() % available_bins];

            bins[bin][sizes[bin]] = n;
            ++sizes[bin];
            for (i = 0; i < sizes[bin]; ++i)
                sums[bin][bins[bin][i] + n] = 1;

            ++n;
        }

        if (n > best)
        {
            best = n;
            for (i = 0; i < k; ++i)
            {
                for (j = 0; j < sizes[i]; ++j)
                    printf("%d ", bins[i][j]);
                printf("\n");
            }
            printf("%u\n", (unsigned)time(NULL));
        }
    }

    return 0;
}

Confirmé n=91, trouvé en 138 secondes. Si nécessaire pour briser l'égalité, je vais retimer pour éviter les grosses erreurs dues à une charge CPU différente.
Peter Taylor

3

C ++, 135

#include <iostream>
#include <cstdlib>
#include <ctime>
#include <cmath>
#include <set>
#include <vector>
#include <algorithm>


using namespace std;

vector<vector<int> > subset;
vector<int> len, tmp;
set<int> sums;

bool is_sum_free_with(int elem, int subnr) {
    sums.clear();
    sums.insert(elem+elem);
    for(int i=0; i<len[subnr]; ++i) {
        sums.insert(subset[subnr][i]+elem);
        for(int j=i; j<len[subnr]; ++j) sums.insert(subset[subnr][i]+subset[subnr][j]);
    }
    if(sums.find(elem)!=sums.end()) return false;
    for(int i=0; i<len[subnr]; ++i) if(sums.find(subset[subnr][i])!=sums.end()) return false;
    return true;
}

int main()
{
    int k = 0; cin >> k;

    int start=time(0);
    cout << start << endl;

    int allmax=0, cnt=0;
    srand(0);

    do {
        len.clear();
        len.resize(k);
        subset.clear();
        subset.resize(k);
        for(int i=0; i<k; ++i) subset[i].resize((int)pow(3, k));

        int n=0, last=0, c, y, g, h, t, max=0;
        vector<int> p(k);

        do {
            ++n;
            c=-1;
            for(int i=0; i++<k; ) {
                y=(last+i)%k;
                if(is_sum_free_with(n, y)) p[++c]=y;
            }

            if(c<0) --n;

            t=n;

            while(c<0) {
                g=rand()%k;
                h=rand()%len[g];
                t=subset[g][h];
                for(int l=h; l<len[g]-1; ++l) subset[g][l]=subset[g][l+1];
                --len[g];
                for(int i=0; i++<k; ) {
                    y=(g+i)%k;
                    if(is_sum_free_with(t, y) && y!=g) p[++c]=y;
                }
                if(c<0) subset[g][len[g]++]=t;
            }

            c=p[rand()%(c+1)];
            subset[c][len[c]++]=t;

            last=c;

            if(n>max) {
                max=n;
                cnt=0;
                if(n>allmax) {
                    allmax=n;
                    for(int i=0; i<k; ++i) {
                        tmp.clear();
                        for(int j=0; j<len[i]; ++j) tmp.push_back(subset[i][j]);
                        sort(tmp.begin(), tmp.end());
                        for(int j=0; j<len[i]; ++j) cout << tmp[j] << " ";
                        cout << endl;
                    }
                    cout << time(0) << " " << time(0)-start << " " << allmax << endl;
                }

            }

        } while(++cnt<50*n && time(0)-start<600);

        cnt=0;

    } while(time(0)-start<600);

    return 0;
}

Ajoute le n suivant à un sous-ensemble choisi au hasard. Si ce n'est pas possible, il supprime les nombres aléatoires des sous-ensembles et les ajoute à d'autres dans l'espoir que cela permet d'ajouter n quelque part.

J'ai prototypé cela en awk, et parce que cela semblait prometteur, je l'ai traduit en C ++ pour l'accélérer. L'utilisation d'un std::setdevrait même l'accélérer davantage.

Sortie pour n = 135 (après environ 230 secondes sur ma [vieille] machine)

2 6 9 10 13 17 24 28 31 35 39 42 43 46 50 57 61 68 75 79 90 94 97 101 105 105 108 119 123 126 127 130 131 134 134 
38 41 45 48 51 52 55 56 58 59 62 64 65 66 67 69 70 71 72 74 78 80 81 84 85 87 88 91 95 98 
5 12 15 16 19 22 23 25 26 29 33 36 73 83 93 100 103 107 110 111 113 114 117 120 121 124 
1 4 11 14 21 27 34 37 40 47 53 60 76 86 89 96 99102109112115122125232135 
3 7 8 18 20 30 32 44 49 54 63 77 82 92104106116118128129133 

Je n'ai pas revérifié la validité, mais ça devrait aller.


2

Python 3, aléatoire gourmand, n = 61

Dernière sortie:

[5, 9, 13, 20, 24, 30, 32, 34, 42, 46, 49, 57, 61]
[8, 12, 14, 23, 25, 44, 45, 47, 54]
[2, 6, 7, 19, 22, 27, 35, 36, 39, 40, 52, 53, 56]
[3, 10, 15, 16, 17, 29, 37, 51, 55, 59, 60]
[1, 4, 11, 18, 21, 26, 28, 31, 33, 38, 41, 43, 48, 50, 58]

Celui-ci utilise effectivement le même algorithme que celui de Martin Büttner , mais je l'ai développé indépendamment.

Il y a des kbacs qui contiennent à la fois les chiffres et les chiffres qui ne peuvent plus y entrer. À chaque profondeur de l'itération (c'est essentiellement une recherche en profondeur d'abord), l'ordre des cases est mélangé et le numéro suivant ( nextN) est (séquentiellement) placé dans les cases qui peuvent le prendre, puis va plus loin. S'il n'y en a pas, il revient, sauvegardant une étape.

from copy import deepcopy
from random import shuffle, seed
from time import clock, time
global maxN
maxN = 0
clock()
seed(0)

def search(k,nextN=1,sets=None):
    global maxN
    if clock() > 600: return

    if nextN == 1: #first iteration
        sets = []
        for i in range(k):
            sets.append([[],[]])

    R = list(range(k))
    shuffle(R)
    for i in R:
        if clock() > 600: return
        if nextN not in sets[i][1]:
            sets2 = deepcopy(sets)
            sets2[i][0].append(nextN)
            sets2[i][1].extend([nextN+j for j in sets2[i][0]])
            nextN2 = nextN + 1

            if nextN > maxN:
                maxN = nextN
                print("New maximum!",maxN)
                for s in sets2: print(s[0])
                print(time())
                print()

            search(k, nextN2, sets2)

search(5)

2

Python, n = 31

import sys
k = int(sys.argv[1])

for i in range(k):
    print ([2**i * (2*j + 1) for j in range(2**(k - i - 1))])

Ok, donc ce n'est visiblement pas un gagnant, mais je sentais que ça appartenait de toute façon. J'ai pris la liberté de ne pas inclure d'horodatage, car il se termine instantanément, et comme ce n'est pas un vrai concurrent.

Tout d'abord, notez que la somme de deux nombres impairs quelconques est paire, afin que nous puissions vider tous les nombres impairs dans le premier bloc. Puis, comme tous les nombres restants sont pairs, nous pouvons les diviser par 2. Encore une fois, nous pouvons jeter tous les nombres impairs résultants dans le deuxième bloc (après les avoir multipliés par 2), diviser les nombres restants par 2 (c'est-à-dire , par 4 au total), jetez les impairs dans le troisième bloc (après les avoir multipliés par 4), et ainsi de suite ... Ou, pour mettre les mots que vous comprenez, nous mettons tous les nombres dont l'ensemble le moins significatif bit est le premier bit du premier bloc, tous les nombres dont le bit défini le moins significatif est le deuxième bit du deuxième bloc, etc.

Pour les blocs k , nous rencontrons des problèmes une fois que nous atteignons n = 2 k , car le bit le moins significatif de n est
le ( k + 1) -ème bit, qui ne correspond à aucun bloc. En d' autres termes, ce système fonctionne jusqu'à
à n = 2 k - 1. Ainsi, alors que pour k = 5 , nous obtenons seulement un maigre n = 31 , ce nombre croît de façon exponentielle avec k . Il établit également que S ( k ) ≥ 2 k - 1 (mais nous pouvons en fait trouver une meilleure limite inférieure que cela assez facilement.)

Pour référence, voici le résultat pour k = 5:

[1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23, 25, 27, 29, 31]
[2, 6, 10, 14, 18, 22, 26, 30]
[4, 12, 20, 28]
[8, 24]
[16]

Il existe un moyen facile d'en extraire un supplémentaire: déplacez la moitié supérieure des nombres impairs dans une autre catégorie (car leur somme est forcément supérieure à tout nombre déjà dans cette catégorie) et ajoutez 2 ^ k à la moitié inférieure de les nombres impairs. La même idée peut probablement être étendue pour obtenir un autre nombre lg k, ou peut-être même un autre k.
Peter Taylor

@PeterTaylor Oui, j'ai réalisé peu de temps après la publication que c'était en fait assez trivial. C'est équivalent à faire [1], [2,3], [4,5,6,7], ..., ce qui est probablement plus simple, juste avec l'ordre inverse des bits et des blocs. Il est facile de voir comment celui-ci peut être étendu.
Ell
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.