Menemukan partisi bebas-jumlah

17

Ringkasan bisnis plan

Input yang diberikan k, cari partisi bilangan bulat 1ke ndalam ksubset bebas jumlah untuk yang terbesar nyang dapat Anda lakukan dalam 10 menit.

Latar belakang: Nomor Schur

Himpunan Aadalah jumlah bebas jika jumlah sendiri A + A = { x + y | x, y in A}tidak memiliki elemen yang sama dengannya.

Untuk setiap bilangan bulat positif kada bilangan bulat terbesar S(k)sehingga himpunan {1, 2, ..., S(k)}dapat dipartisi menjadi khimpunan bagian bebas jumlah. Jumlah ini disebut k th jumlah Schur (Oei A045652 ).

Misalnya S(2) = 4,. Kita dapat mempartisi {1, 2, 3, 4}sebagai {1, 4}, {2, 3}, dan itu adalah partisi unik menjadi dua himpunan bagian jumlah bebas, tetapi sekarang kita tidak dapat menambahkan 5ke bagian mana pun.

Tantangan

Tulis program deterministik yang melakukan hal berikut:

  • Ambil bilangan bulat positif ksebagai input
  • Tulis stempel waktu Unix saat ini ke stdout
  • Keluarkan urutan partisi 1menjadi nke ksubset bebas jumlah untuk bertambah n, mengikuti setiap urutan dengan cap waktu Unix saat ini.

Pemenangnya adalah program yang mencetak partisi terbesar ndalam waktu 10 menit di komputer saya ketika diberi input 5. Ikatan akan terputus dengan waktu tercepat untuk menemukan partisi untuk yang terbesar n, rata-rata lebih dari tiga kali: itu sebabnya output harus menyertakan cap waktu.

Detail penting:

  • Saya memiliki Ubuntu Precise, jadi jika bahasa Anda tidak didukung, saya tidak akan bisa menilai itu.
  • Saya memiliki Intel Core2 Quad CPU, jadi jika Anda ingin menggunakan multithreading tidak ada gunanya menggunakan lebih dari 4 utas.
  • Jika Anda ingin saya menggunakan flag compiler atau implementasi tertentu, dokumentasikan dengan jelas dalam jawaban Anda.
  • Anda tidak akan membuat kasus khusus kode Anda untuk menangani input 5.
  • Anda tidak perlu menampilkan setiap peningkatan yang Anda temukan. Misalnya untuk input, 2Anda hanya bisa menampilkan partisi untuk n = 4. Namun, jika Anda tidak menghasilkan apa pun dalam 10 menit pertama maka saya akan menilai itu sebagai n = 0.
Peter Taylor
sumber

Jawaban:

8

Python 3, urutkan berdasarkan angka terbesar, n = 92 121

Terima kasih kepada Martin Büttner untuk saran yang secara tak terduga meningkatkan jumlah maksimum yang ndicapai.

Output terakhir:

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

Algoritmanya sama dengan jawaban saya sebelumnya, yang dikutip di bawah ini:

Ada k bin yang memiliki nomor di dalamnya sejauh ini dan angka yang tidak bisa masuk lagi. Pada setiap kedalaman dalam iterasi (pada dasarnya ini adalah pencarian mendalam-pertama), pemesanan bin dikocok dan nomor berikutnya (nextN) dimasukkan (secara berurutan) ke dalam tempat sampah yang dapat mengambilnya dan kemudian melangkah satu langkah lebih dalam. Jika tidak ada, itu kembali, mendukung satu langkah.

... dengan satu pengecualian: pemesanan nampan tidak dikocok. Sebaliknya, itu diurutkan sedemikian rupa sehingga tempat sampah dengan jumlah terbesar datang terlebih dahulu. Ini tercapai n = 121dalam 8 detik!

Kode:

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)
El'endia Starman
sumber
Catatan: menyortir oleh jumlah terbesar nomor diperbolehkan dalam kisaran angka tidak diperbolehkan memberi n=59, dan penyortiran oleh jumlah terbesar nomor diperbolehkan kurang dari nextNmemberi n=64. Mengurutkan berdasarkan panjang daftar angka yang tidak diizinkan (yang mungkin memiliki pengulangan) mengarah sangat cepat ke n=30pola yang elegan .
El'endia Starman
Format waktu keluaran tidak benar (seharusnya detik sejak zaman, tapi saya melihat Tue Nov 10 00:44:25 2015), tapi saya melihat n=92dalam waktu kurang dari 2 detik.
Peter Taylor
Ah, saya pikir format waktu tidak sepenting menunjukkan berapa lama waktu yang dibutuhkan. Saya akan mencari tahu dan mengubahnya. EDIT: D'oh. Aku mengambil ctimelebih timekarena output lebih cantik ketika timeitu persis apa yang saya harus sudah memilih.
El'endia Starman
Anda tahu, Anda juga bisa hanya mengurutkan berdasarkan jumlah terbesar di tempat sampah, karena jumlah terbesar yang ditolak akan selalu dua kali lipat.
Martin Ender
@ MartinBüttner: ...... Saya ... eh ... Saya tidak tahu bagaimana atau mengapa, tapi itu bisa n=121. oO
El'endia Starman
7

Python 3, 121, <0,001s

Peningkatan heuristik berkat Martin Buttner berarti kita bahkan tidak perlu keacakan.

Keluaran:

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

Kode:

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

Urutkan berdasarkan jumlah dari 2 elemen pertama + condong

[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

Saya menyalin struktur data El'endia Starman, yang terdiri dari daftar pasangan, di mana elemen pertama dari pasangan adalah elemen dalam ember itu, dan yang kedua adalah jumlah dari ember itu.

Saya mulai dengan pendekatan "lacak jumlah yang tersedia" yang sama. Heuristik sorting saya hanyalah jumlah dari dua elemen terkecil dalam daftar yang diberikan. Saya juga menambahkan condong acak kecil untuk mencoba berbagai kemungkinan.

Setiap iterasi hanya menempatkan setiap nomor baru di nampan pertama yang tersedia, mirip dengan serakah acak. Setelah ini gagal, itu hanya restart.

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
isaacg
sumber
Wow, ini terlihat sangat mirip dengan kode saya. : P;) (Saya tidak keberatan sama sekali.)
El'endia Starman
@ El'endiaStarman Credit menambahkan. Dasar yang bagus.
isaacg
7

Java 8, n = 142 144

Output terakhir:

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

Melakukan pencarian acak unggulan yang didistribusikan di lebih dari 4 utas. Ketika tidak dapat menemukan partisi yang cocok, nia mencoba untuk membebaskan ruang ndalam satu partisi pada satu waktu dengan membuang sebanyak mungkin dari itu ke partisi lain.

sunting: tweak algoritma untuk membebaskan ruang untuk n, juga menambahkan kemampuan untuk kembali ke pilihan sebelumnya dan memilih lagi.

catatan: output tidak sepenuhnya deterministik karena ada beberapa utas yang terlibat dan mereka akhirnya memperbarui yang terbaik yang nditemukan sejauh ini dalam urutan yang campur aduk; skor akhirnya 144 adalah deterministik dan dicapai dengan cukup cepat: 30 detik di komputer saya.

Kode adalah:

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

C, serakah acak, n = 91

Hanya untuk memberikan solusi dasar, ini berulang n, melacak sampah dan jumlah mereka dan menambahkan nke bin acak di mana ia belum muncul sebagai jumlah. Ini berakhir sekali nmuncul dalam semua kjumlah, dan jika hasilnya nlebih baik daripada upaya sebelumnya, mencetaknya ke STDOUT.

Input kdiberikan melalui argumen baris perintah. Maksimum yang mungkin ksaat ini hardcoded ke 10 karena saya terlalu malas menambahkan alokasi memori dinamis, tetapi itu bisa diperbaiki dengan mudah.

Saya kira saya bisa pergi berburu benih yang lebih baik sekarang, tapi jawaban ini mungkin tidak terlalu kompetitif, jadi meh.

Ini adalah partisi untuk 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

Dan akhirnya, inilah kodenya:

#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;
}
Martin Ender
sumber
Dikonfirmasi n=91, ditemukan dalam 138 detik. Jika perlu untuk tie-breaking saya akan retime untuk menghindari kesalahan besar karena beban CPU yang berbeda.
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;
}

Tambahkan n berikutnya ke subset yang dipilih secara acak. Jika itu tidak memungkinkan, ia menghapus angka acak dari himpunan bagian dan menambahkannya ke orang lain dengan harapan hal itu memungkinkan penambahan di suatu tempat.

Saya membuat prototipe dalam awk, dan karena terlihat menjanjikan, saya menerjemahkannya ke dalam C ++ untuk mempercepatnya. Menggunakan std::setbahkan harus mempercepat lebih.

Output untuk n = 135 (setelah sekitar 230 detik pada mesin [lama] saya)

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 113 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 

Saya tidak memeriksa ulang validitasnya, tetapi seharusnya tidak apa-apa.

Cabbie407
sumber
2

Python 3, serakah acak, n = 61

Output terakhir:

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

Ini menggunakan secara efektif algoritma yang sama dengan algoritma Martin Büttner , tetapi saya mengembangkannya secara independen.

Ada ktempat sampah yang memiliki nomor di dalamnya sejauh ini dan nomor yang tidak bisa masuk lagi. Pada setiap kedalaman dalam iterasi (pada dasarnya ini adalah pencarian mendalam-pertama), pemesanan bin dikocok dan nomor berikutnya nextN() dimasukkan (secara berurutan) ke dalam tempat sampah yang dapat mengambilnya dan kemudian melangkah lebih dalam satu langkah. Jika tidak ada, itu kembali, mendukung satu langkah.

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)
El'endia Starman
sumber
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, jadi itu obvisouly bukan pemenang, tetapi saya merasa itu milik di sini pula. Saya telah mengambil kebebasan untuk tidak memasukkan stempel waktu, karena itu berakhir secara instan, dan karena itu bukan pesaing nyata.

Pertama, perhatikan bahwa jumlah dua angka ganjil mana pun adalah genap, sehingga kami dapat membuang semua angka ganjil di blok pertama. Kemudian, karena semua angka yang tersisa adalah genap, kita dapat membaginya dengan 2. Sekali lagi, kita dapat membuang semua angka ganjil yang dihasilkan di blok kedua (setelah mengalikannya dengan 2), membagi angka yang tersisa dengan 2 (yaitu , dengan 4 keseluruhan), melempar yang aneh di blok ketiga (setelah mengalikannya dengan 4), dan seterusnya ... Atau, dengan kata-kata yang kalian mengerti, kami menempatkan semua angka yang set paling tidak signifikan bit adalah bit pertama di blok pertama, semua angka yang bit set paling tidak signifikan adalah bit kedua di blok kedua, dan seterusnya ...

Untuk blok k , kita mengalami masalah setelah mencapai n = 2 k , karena bit set paling tidak signifikan dari n adalah bit
( k + 1) -th, yang tidak sesuai dengan blok mana pun. Dengan kata lain, skema ini bekerja sampai
ke n = 2 k - 1. Jadi, sedangkan untuk k = 5 kita hanya mendapatkan sedikit n = 31 , jumlah ini tumbuh secara eksponensial dengan k . Ini juga menetapkan bahwa S ( k ) ≥ 2 k - 1 (tetapi kita sebenarnya dapat menemukan batas bawah yang lebih baik daripada itu dengan mudah.)

Untuk referensi, inilah hasil untuk 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]
Elo
sumber
Ada cara mudah untuk memeras satu ekstra: pindahkan bagian atas dari angka ganjil ke kategori lain (karena jumlah mereka pasti lebih besar daripada angka yang sudah ada di kategori itu) dan tambahkan 2 ^ k ke bagian bawah dari angka ganjil. Gagasan yang sama mungkin dapat diperluas untuk mendapatkan angka lg k lain, atau mungkin bahkan k yang lain.
Peter Taylor
@PeterTaylor Ya, saya baru sadar setelah memposting bahwa ini sebenarnya sangat sepele. Ini setara dengan melakukan [1], [2,3], [4,5,6,7], ..., yang mungkin lebih sederhana, hanya dengan bit terbalik dan ketertiban blok. Sangat mudah untuk melihat bagaimana ini dapat diperpanjang.
Ell