Toplamsız bölüm bulma


17

Yönetici Özeti

Giriş Verilen k, tamsayılar bir bölümü bulmak 1için niçine kbüyük-toplamı serbest alt kümeleri n10 dakika içinde yapabilirsiniz.

Arka plan: Schur numaraları

Bir dizi Aolan toplamı içermeyen kendiliğinden toplamı iseA + A = { x + y | x, y in A} onunla ortak hiçbir elemanları vardır.

Her pozitif tamsayı için, kümenin toplamsız altkümelere bölünebileceği en kbüyük bir tamsayı vardır . Bu sayı k denir inci Schur numarası (OEIS A045652 ).S(k){1, 2, ..., S(k)}k

Örneğin S(2) = 4,. {1, 2, 3, 4}Olarak bölümleyebiliriz {1, 4}, {2, 3}ve bu iki toplamsız alt kümeye benzersiz bölümdür, ancak şimdi 5her iki bölüme de bir ekleyemeyiz .

Meydan okuma

Aşağıdakileri yapan deterministik bir program yazın :

  • kGirdi olarak pozitif bir tamsayı alın
  • Geçerli Unix zaman damgasını stdout'a yazma
  • Bir bölüm, bir dizi çıkışları 1için niçine kartırmak için toplam içermeyen alt-n akım UNIX zaman etiketleri dizisi takip edilerek,.

Kazanan, ngirdi verildiğinde bilgisayarımda 10 dakika içinde en büyüğü için bir bölüm yazdıran program olacak 5. Bağlar, en büyükler için bir bölüm bulmak için en kısa sürede kırılacakn üç koşu boyunca ortalama , : bu nedenle çıktı zaman damgalarını içermelidir.

Önemli ayrıntılar:

  • Ubuntu Precise'a sahibim, bu nedenle diliniz desteklenmiyorsa puan veremem.
  • Intel Core2 Quad CPU'm var, bu yüzden multithreading kullanmak istiyorsanız 4'ten fazla iş parçacığı kullanmanın bir anlamı yok.
  • Herhangi bir derleyici bayrağını veya uygulamasını kullanmamı istiyorsanız, cevabınızda açıkça belirtin.
  • Girdiyi işlemek için kodunuzu özel olarak kullanamazsınız 5 .
  • Bulduğunuz her iyileştirmenin çıktısını almanız gerekmez. Örneğin giriş için 2yalnızca bölümün çıktısını alabilirsiniz n = 4. Ancak, ilk 10 dakika içinde hiçbir şey çıkarmazsanız, o zaman puan vereceğim n = 0.

Yanıtlar:


8

Sıralama büyük çoğunluğunun Python 3, n = 92 121

Martin Büttner'e nulaşılan maksimum süreyi beklenmedik şekilde iyileştiren bir öneri için teşekkürler .

Son çıktı:

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

Algoritma, aşağıda belirtilen önceki cevabımla aynı:

Hem şimdiye kadar hem de artık giremeyen sayılara sahip k bidonları var. Yinelemedeki her derinlikte (temelde önce derinlik araması), çöp kutusu sıralaması karıştırılır ve sonraki sayı (nextN), onu alabilen kutulara konur ve daha sonra bir adım daha derine gider. Hiçbiri yoksa, bir adım geri döner.

... bir istisna dışında: bin sipariş edilir değil karıştırdı. Bunun yerine, en fazla sayıdaki çöp kutularının önce geleceği şekilde sıralanır . Bu 8 saniyeye ulaştı !n = 121

Kod:

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)

Not: izin verilmeyen sayı aralığı verir içinde izin sayıların büyük çoğunluğunun sıralama n=59ve daha az izin sayıların en fazla sayıdaki göre sıralama nextNverir n=64. İzin verilmeyen sayılar listesinin uzunluğuna göre (tekrarlar olabilir) sıralama çok hızlı bir şekilde zarif bir n=30desene yol açar .
El'endia Starman

Çıktı zaman formatı doğru değil (çağdan beri saniye olmalı, ama görüyorum Tue Nov 10 00:44:25 2015), ancak n=922 saniyeden daha kısa sürede gördüm .
Peter Taylor

Ah, zaman formatının tam olarak ne kadar sürdüğünü göstermek kadar önemli olmadığını düşündüm. Ben çözeceğim ve değiştireceğim. DÜZENLEME: D'oh. Ben aldım ctimeüzerinde timezaman çıkış daha güzeldi çünkü timeben aldı gerekirdi tam olarak ne.
El'endia Starman

Bilirsiniz, çöp kutusundaki en büyük sayıya göre de sıralayabilirsiniz, çünkü izin verilmeyen en büyük sayı her zaman bunun iki katı olacaktır.
Martin Ender

@ MartinBüttner: ...... Ben ... ah ... nasıl ya da neden olduğu hakkında hiçbir fikrim yok, ama bu oluyor n=121. oO
El'endia Starman

7

Python 3, 121, <0.001s

Martin Buttner sayesinde iyileştirilmiş sezgisel tarama, rasgeleliğe bile ihtiyacımız olmadığı anlamına gelir.

Çıktı:

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

Kod:

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

İlk 2 öğenin toplamına göre sırala + eğrilt

[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'ın çiftler listesinden oluşan veri yapısını kopyaladım, burada çiftin ilk elemanı o kovadaki elemanlar ve ikincisi o kovadaki toplamlar.

Aynı "hangi meblağların mevcut olduğunu takip et" yaklaşımıyla başlıyorum. Benim sezgisel ayırma yöntemim, belirli bir listedeki en küçük iki öğenin toplamıdır. Ayrıca farklı olasılıkları denemek için küçük bir rastgele çarpıklık ekliyorum.

Her yineleme, rastgele açgözlüğe benzer şekilde, her yeni sayıyı ilk avalible bölmeye yerleştirir. Bu başarısız olduğunda, yeniden başlar.

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

Vay canına, bu benim koduma çok benziyor. : P;) (Hiç umrumda değil.)
El'endia Starman

@ El'endiaStarman Kredisi eklendi. Güzel bir temel.
isaacg

7

Java 8, n = 142 144

Son çıktı:

@ 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 iş parçacığına dağıtılmış tohumlanmış rastgele arama gerçekleştirir. İçine sığacak bir bölüm bulamadığında n,n diğer bölümlere olabildiğince dışarı kadar onun gibi damping tarafından bir seferde bir bölümünde.

düzenleme: alan boşaltmak için algoritma tweaked n açmak , ayrıca önceki bir seçim geri dönüp tekrar seçim yeteneği ekledi.

not: çıktı kesinlikle deterministik değildir çünkü dahil birden fazla iş parçacığı vardır ve onlar nşimdiye kadar bulunan en iyi güncellenen güncellemek sonunda karışıklık; 144'lük nihai puan belirleyici olmakla birlikte oldukça hızlı bir şekilde ulaşılır: bilgisayarımda 30 saniye.

Kod:

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, Rastgele Açgözlü, n = 91

Sadece bir temel çözüm sağlamak için, bu, tekrarlar n, kutuları ve toplamlarını takip eder ve nhenüz bir toplam olarak görünmediği rastgele bir kutuya ekler . Bir kez ntüm kmeblağlarda görünür ve sonuçta ortaya çıkarsan önceki herhangi bir denemeden daha iyiyse, STDOUT'a yazdırır.

Giriş kbir komut satırı argümanı ile sağlanır. Maksimum ktembel dinamik bellek ayırma eklemek için tembel olduğum için şu anda mümkün olan maksimum 10 kodlanmış, ancak bu kolayca düzeltilebilir.

Sanırım şimdi daha iyi bir tohum için avlanmaya gidebilirdim, ama bu cevap muhtemelen özellikle rekabetçi değil, yani meh.

İşte bölüm 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

Ve son olarak, kod İşte:

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

Onaylandı n=91, 138 saniye içinde bulundu. Bağlama için gerekirse, farklı CPU yükü nedeniyle büyük hataları önlemek için yeniden çalıştıracağım.
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;
}

Sıradaki n'yi rastgele seçilen bir alt kümeye ekler. Bu mümkün değilse, rasgele sayıları alt kümelerden kaldırır ve başka bir yere n eklemeyi umarak başkalarına ekler.

Bunu awk olarak prototipledim ve umut verici göründüğü için, hızlandırmak için C ++ 'a çevirdim. Bir kullanarak std::setbunu daha da hızlandırmalısınız.

N = 135 için çıktı ([eski] makinemde yaklaşık 230 saniye sonra)

2 6 9 10 13 17 24 28 31 35 39 42 43 46 50 57 61 68 75 79 90 94 971010105114111212121212121313133 
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 931001031071011111111111171201212124 
1 4 11 14 21 27 34 37 40 47 53 60 76 86 89 96 991021021211512112125135135 
3 7 8 18 20 30 32 44 49 54 63 77 82 92104106 1161111121212133 

Geçerliliği tekrar kontrol etmedim, ama iyi olmalı.


2

Python 3, rastgele açgözlü, n = 61

Son çıktı:

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

Bu Martin Büttner ile aynı algoritmayı etkili bir şekilde kullanır , ancak bağımsız olarak geliştirdim.

kŞimdiye kadar hem sayıların hem de artık içeri giremeyen sayıların bulunduğu kutular var. Yinelemedeki her derinlikte (temelde önce derinlik araması), çöp kutusu sıralaması karıştırılır ve bir sonraki sayı ( nextN) sırayla alabilen kutulara konur ve bir adım daha derine iner. Hiçbiri yoksa, bir adım geri döner.

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

Tamam, bu açıkça bir kazanan değil, ama yine de buraya ait olduğunu hissettim. Anında sona erdiğinden ve gerçek bir yarışmacı olmadığından, zaman damgalarını dahil etmeme özgürlüğünü aldım.

İlk olarak, herhangi bir iki tek sayının toplamının çift olduğunu unutmayın, böylece tüm tek sayıları ilk bloğa dökebiliriz. Daha sonra, kalan tüm sayılar çift olduğu için, bunları 2'ye bölebiliriz. Bir kez daha, elde edilen tüm tek sayıları ikinci blokta atayabiliriz (bunları 2 ile çarptıktan sonra), kalan sayıları 2'ye böleriz (yani , genel olarak 4), garip olanları üçüncü blokta atın (bunları 4 ile çarptıktan sonra) ve benzeri ... Veya, anladığınız sözcükleri koymak için, en az anlamlı olan tüm sayıları koyarız bit, ilk bloktaki ilk bittir, en az anlamlı set biti ikinci bloktaki ikinci bit olan tüm sayılardır, vb.

İçin k biz ulaştığında blok biz sorun çalıştırmak n = 2 , k 'nin en az önemli bit, çünkü, n olan
( k bir bloğa karşılık gelmeyen + 1) inci biti. Başka bir deyişle, bu şema kadar çalışır
üzere n = 2 k için ise, 1. So - k = 5 sadece yetersiz bir olsun n = 31 bu sayı ile katlanarak büyür, k . Ayrıca S ( k ) ≥ 2 k - 1 olduğunu tespit eder (ancak aslında bundan daha iyi bir alt limit bulabiliriz.)

Referans olarak, k = 5 için sonuç :

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

Ekstra bir tane sıkıştırmanın kolay bir yolu vardır: tek sayıların üst yarısını başka bir kategoriye taşıyın (toplamları o kategorideki herhangi bir sayıdan daha büyük olması gerektiğinden) ve alt yarısına 2 ^ k ekleyin tek sayılar. Aynı fikir muhtemelen başka bir lg k numarası, hatta belki başka bir k almak için genişletilebilir.
Peter Taylor

@PeterTaylor Evet, gönderdikten kısa bir süre sonra bunun gerçekten önemsiz olduğunu fark ettim. Sadece [1], [2,3], [4,5,6,7], ...ters bit ve blok sırası ile, muhtemelen daha basit olan yapmaya eşdeğerdir . Bunun nasıl genişletilebileceğini görmek kolaydır.
Ell
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.