Пошук розділів без сум


17

Резюме

З урахуванням введенням k, знайти розбиття чисел 1на nв kвільних від сум , підмножин найбільшого nви можете в протягом 10 хвилин.

Передумови: номери Шура

Набір Aбез суми, якщо його сума-сума A + A = { x + y | x, y in A}не має спільних з ним елементів.

На кожне додатне ціле число kіснує найбільше ціле число, S(k)таке, що набір {1, 2, ..., S(k)}можна розділити на kбезмножинні підмножини. Це число називається k- м номером Шура (OEIS A045652 ).

Наприклад, S(2) = 4. Ми можемо розділити {1, 2, 3, 4}як {1, 4}, {2, 3}, і це унікальний розділ на два безмножинні підмножини, але тепер ми не можемо додати 5до жодної частини.

Виклик

Напишіть детерміновану програму, яка робить наступне:

  • Візьміть натуральне число kяк вхідне
  • Напишіть поточну мітку Unix для stdout
  • Виходи послідовності розбиттів 1до nInto , kвільні від сум підмножин для збільшення n, після кожної послідовності з поточної тимчасової міткою Unix.

Переможцем стане програма, яка надрукує розділ для найбільшого nпротягом 10 хвилин на моєму комп’ютері при даному введенні 5. Зв'язки будуть порушені в найшвидший час, щоб знайти розділ для найбільшого n, усередненого за три запуски: тому висновок повинен включати часові позначки.

Важливі деталі:

  • У мене є Ubuntu Precision, тому якщо ваша мова не підтримується, я не зможу її оцінити.
  • У мене є процесор Intel Core2 Quad Quad, тому якщо ви хочете використовувати багатопотоковість, немає сенсу використовувати більше 4 потоків.
  • Якщо ви хочете, щоб я використовував якісь конкретні прапори компілятора чи реалізацію, документуйте це чітко у своїй відповіді.
  • Ви не маєте особливого обліку свого коду для обробки даних 5.
  • Від вас не вимагається виводити кожне покращення, яке ви знайдете. Наприклад, для введення 2ви можете вивести тільки розділ n = 4. Однак, якщо ви нічого не виведете за перші 10 хвилин, то я зарахую це як n = 0.

Відповіді:


8

Python 3, сортування за найбільшою кількістю, n = 92 121

Дякую Мартіну Бюттнеру за пропозицію, яка несподівано покращила nдосягнутий максимум .

Останній вихід:

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

Алгоритм такий самий, як і в попередній моїй відповіді, цитований нижче:

Є k бункерів, у яких поки що є номери, і числа, які більше не можуть входити в нього. На кожній глибині ітерації (це в основному пошук на глибині), впорядкування відходів перетасовується, а наступне число (наступнеN) (послідовно) вставляється в бункери, які можуть взяти його, а потім йде на крок глибше. Якщо таких немає, він повертається, резервуючи один крок.

... за одним винятком: упорядкування відходів не переміщується. Натомість так і є сортується таким чином, що першими виходять бункери з найбільшою кількістю . Це досяг n = 121за 8 секунд!

Код:

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)

Примітка: сортування за найбільшою кількістю дозволених чисел у межах заборонених чисел дає n=59та сортування за найбільшою кількістю дозволених чисел, меншою, ніж nextNдає n=64. Сортування за довжиною списку заборонених чисел (яке може мати повтори) дуже швидко призводить до елегантного n=30малюнка.
El'endia Starman

Формат часу виходу невірний (має бути секунд з епохи, але я бачу Tue Nov 10 00:44:25 2015), але я побачив n=92менше ніж за 2 секунди.
Пітер Тейлор

Ага, я подумав, що формат часу не такий важливий, як точно показувати, скільки часу потрібно. Я це зрозумію і зміню. РЕДАКТ: D'oh. Я вибрав ctimeбільш , timeтому що вихід був симпатичніше , коли timeбуло саме те , що я повинен вибрав.
El'endia Starman

Ви знаєте, ви також можете просто сортувати за найбільшою кількістю у смітнику, тому що найбільше заборонене число завжди буде вдвічі більшим.
Мартін Ендер

@ MartinBüttner: ...... Я ... е-е ... я поняття не маю як і чому, але це виходить n=121. оо
El'endia Starman

7

Пітон 3, 121, <0,001с

Покращена евристичність завдяки Мартіну Баттнеру означає, що нам навіть не потрібна випадковість.

Вихід:

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

Код:

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

Пітон 3, 112

Сортувати за сумою перших 2 елементів + ​​перекос

[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

Я скопіював структуру даних El'endia Starman, яка складається із списку пар, де перший елемент пари - це елементи у цьому відрі, а другий - суми цього відра.

Я починаю з того ж підходу "відстежувати, які суми доступні". Моє евристичне сортування - це просто сума найменших двох елементів у даному списку. Я також додаю невеликий випадковий перекіс, щоб спробувати різні можливості.

Кожна ітерація просто поміщає кожен новий номер у перший доступний контейнер, подібний до випадкового жадібного. Як тільки це не вдається, він просто перезавантажується.

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

Ого, це виглядає надзвичайно схоже на мій код. : P;) (Я зовсім не проти.)
El'endia Starman

@ El'endiaStarman Credit додано. Це приємна основа.
isaacg

7

Ява 8, n = 142 144

Останній вихід:

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

Здійснює насіннєвий випадковий пошук, розподілений на 4 потоки. Коли він не може знайти розділ, який би вмістився, nвін намагається звільнити місце дляn одного розділу за один раз, скидаючи стільки, скільки може з нього в інші розділи.

редагувати: налаштовано алгоритм звільнення місця для n , також додано можливість повернутися до попереднього вибору та вибрати знову.

зауважте: вихід не є суворо детермінованим, оскільки в ньому задіяно декілька потоків, і вони можуть закінчитись оновленням найкращого nзнайденого на даний момент у змішаному порядку; остаточний бал 144 є детермінованим, але він досягається досить швидко: 30 секунд на моєму комп’ютері.

Код:

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, Випадкова жадібність, n = 91

Просто, щоб забезпечити базове рішення, це повторюється n, слідкуючи за бункерами та їх сумами, і додає nдо випадкової скриньки, де вона ще не відображається як сума. Він закінчується один раз, nз'являється в усіх kсумах, і якщо в результатіn був кращим, ніж будь-яка попередня спроба, надрукує його на STDOUT.

Введення kнадається через аргумент командного рядка. Наразі максимально можливе kкодування до 10, тому що я лінивий додав динамічний розподіл пам'яті, але це можна було легко виправити.

Я здогадуюсь, я міг би зараз піти на полювання на краще насіння, але ця відповідь, мабуть, не є особливо конкурентоспроможною, так що мені.

Ось розділ для 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

І нарешті, ось код:

#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;
}

Підтверджено n=91, знайдено за 138 секунд. Якщо потрібно для розриву зв'язків, я перейму, щоб уникнути великих помилок через різну завантаженість процесора.
Пітер Тейлор

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

Додає наступне n до випадково вибраного підмножини. Якщо це неможливо, він видаляє випадкові числа з підмножини та додає їх іншим, сподіваючись, що це дозволить десь додати n.

Я прототипував це дивним способом, і оскільки це виглядало багатообіцяюче, я переклав це на C ++, щоб пришвидшити його. Використання A std::setнавіть повинно прискорити його більше.

Вихід за n = 135 (приблизно через 230 секунд на моїй [старій] машині)

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 108 119 123 126 127 130 131 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 111 114 114 117 120 121 124 
1 4 11 14 21 27 34 37 40 47 53 60 76 86 89 96 99 102 109 112 115 122 125 132 135 
3 7 8 18 20 30 32 44 49 54 63 77 82 92 104 106 116 118 128 129 133 

Я не перевіряв дійсність, але це повинно бути добре.


2

Пітон 3, випадковий жадібний, n = 61

Останній вихід:

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

При цьому ефективно використовується той же алгоритм, що і у Мартина Бюттнера , але я розробив його самостійно.

Є kбункери, в яких поки що є номери, і номери, які більше не можуть входити в нього. На кожній глибині ітерації (це в основному пошук на глибині), впорядкування nextNвідходів переміщується, а наступне число ( ) (послідовно) вставляється в бункери, які можуть взяти його, а потім піде на один крок глибше. Якщо таких немає, він повертається, резервуючи один крок.

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

Пітон, 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))])

Гаразд, так це очевидно, що не переможець, але я відчував, що йому тут належить. Я взяв на себе сміття не включати часові позначки, оскільки воно миттєво припиняється, і оскільки це не справжній претендент.

По-перше, зауважте, що сума будь-яких двох непарних чисел є парною, тому ми можемо скинути всі непарні числа в перший блок. Потім, оскільки всі решта числа є парними, ми можемо розділити їх на 2. Ще раз, ми можемо кинути всі отримані непарні числа у другий блок (після повторного їх множення на 2), ділимо інші числа на 2 (тобто , на 4 загалом), киньте непарні в третій блок (після їх повторного множення на 4) і так далі ... Або, якщо ви зрозуміли, ви, хлопці, слова, ми ставимо всі числа, найменш значущий набір біт - це перший біт у першому блоці, усі числа, найменш значущим набором яких є другий біт у другому блоці, і так далі ...

Для k блоків ми стикаємося з проблемою, як тільки досягнемо n = 2 k , оскільки найменш значущим набором біт n є
( k + 1)-біт, який не відповідає жодному блоку. Іншими словами, ця схема працює
до n = 2 k - 1. Отже, хоча при k = 5 ми отримуємо лише мізерні n = 31 , це число зростає експоненціально з k . Він також встановлює, що S ( k ) ≥ 2 k - 1 (але насправді ми можемо знайти кращу нижню межу, ніж це досить легко.)

Для довідки, ось результат для 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]

Існує простий спосіб видавити зайвий: перенесіть верхню половину непарних чисел на будь-яку іншу категорію (оскільки їхня сума повинна бути більшою, ніж будь-яке число, що вже в цій категорії), і додайте 2 ^ k до нижньої половини непарні числа. Таку саму ідею, ймовірно, можна поширити, щоб отримати ще одна lg k чисел, а може навіть ще k.
Пітер Тейлор

@PeterTaylor Так, я зрозумів, невдовзі після публікації, що це насправді досить тривіально. Це рівнозначно виконанню [1], [2,3], [4,5,6,7], ..., що, мабуть, простіше, лише з реверсом і порядком блоку. Неважко зрозуміти, як це можна продовжити.
Ell
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.