Tìm phân vùng tổng hợp


17

Tóm tắt

Với đầu vào k, tìm một phân vùng của các số nguyên 1để nthành ktập con tổng hợp miễn phí cho lớn nhất nbạn có thể trong vòng 10 phút.

Bối cảnh: Số Schur

Một tập hợp Atổng miễn phí nếu tự tổng của A + A = { x + y | x, y in A}nó không có phần tử chung với nó.

Đối với mỗi số nguyên dương kcó một số nguyên lớn nhất S(k)sao cho tập hợp {1, 2, ..., S(k)}có thể được phân chia thành kcác tập con không có tổng. Số này được gọi là số Schur thứ k (OEIS A045652 ).

Ví dụ , S(2) = 4. Chúng ta có thể phân vùng {1, 2, 3, 4}dưới dạng {1, 4}, {2, 3}, và đó là phân vùng duy nhất thành hai tập con không có tổng, nhưng bây giờ chúng ta không thể thêm một 5vào một trong hai phần.

Thử thách

Viết chương trình xác định thực hiện như sau:

  • Lấy số nguyên dương klàm đầu vào
  • Viết dấu thời gian Unix hiện tại vào thiết bị xuất chuẩn
  • Kết quả đầu ra một chuỗi các phân vùng của 1để nvào ktập con tổng hợp miễn phí cho tăng n, sau mỗi chuỗi với dấu thời gian Unix hiện hành.

Người chiến thắng sẽ là chương trình in phân vùng lớn nhất ntrong vòng 10 phút trên máy tính của tôi khi được đưa vào đầu vào 5. Các mối quan hệ sẽ bị phá vỡ trong thời gian nhanh nhất để tìm một phân vùng lớn nhất n, tính trung bình trong ba lần chạy: đó là lý do tại sao đầu ra phải bao gồm dấu thời gian.

Chi tiết quan trọng:

  • Tôi có Ubuntu Precise, vì vậy nếu ngôn ngữ của bạn không được hỗ trợ, tôi sẽ không thể chấm điểm.
  • Tôi có CPU Intel Core2 Quad, vì vậy nếu bạn muốn sử dụng đa luồng thì không có điểm nào sử dụng nhiều hơn 4 luồng.
  • Nếu bạn muốn tôi sử dụng bất kỳ cờ trình biên dịch cụ thể hoặc triển khai nào, hãy ghi lại rõ ràng trong câu trả lời của bạn.
  • Bạn sẽ không đặc biệt mã của bạn để xử lý đầu vào 5.
  • Bạn không cần phải xuất ra mọi cải tiến bạn tìm thấy. Ví dụ, đối với đầu vào, 2bạn chỉ có thể xuất phân vùng cho n = 4. Tuy nhiên, nếu bạn không xuất bất cứ thứ gì trong 10 phút đầu tiên thì tôi sẽ ghi điểm đó n = 0.

Câu trả lời:


8

Python 3, sắp xếp theo số lớn nhất, n = 92 121

Cảm ơn Martin Büttner cho một đề nghị bất ngờ cải thiện tối đa nđạt được.

Đầu ra cuối cùng:

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

Thuật toán giống như câu trả lời trước của tôi, được trích dẫn dưới đây:

Có những thùng k có cả hai số trong đó cho đến nay và những số không thể đi trong đó nữa. Ở mỗi độ sâu trong lần lặp (về cơ bản là tìm kiếm theo chiều sâu), thứ tự bin được xáo trộn và số tiếp theo (nextN) được đặt vào các thùng có thể lấy nó và sau đó tiến sâu hơn một bước. Nếu không có, nó trả về, sao lưu một bước.

... Với một ngoại lệ: thứ tự bin không bị xáo trộn. Thay vào đó, nó được sắp xếp theo cách mà các thùng có số lượng lớn nhất đến trước. Điều này đạt được n = 121trong 8 giây!

Mã số:

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)

Lưu ý: sắp xếp theo số lượng lớn nhất của các số được phép trong phạm vi số không được phép đưa ra n=59và sắp xếp theo số lượng lớn nhất của số được phép ít hơn số nextNcho n=64. Sắp xếp theo độ dài của danh sách số không được phép (có thể lặp lại) dẫn rất nhanh đến một n=30mẫu thanh lịch .
El'endia Starman

Định dạng thời gian đầu ra không chính xác (nên là giây kể từ kỷ nguyên, nhưng tôi đang thấy Tue Nov 10 00:44:25 2015), nhưng tôi đã thấy n=92trong chưa đầy 2 giây.
Peter Taylor

Ah, tôi đoán rằng định dạng thời gian không quan trọng bằng việc hiển thị chính xác thời gian mất bao lâu. Tôi sẽ tìm ra nó và thay đổi nó mặc dù. CHỈNH SỬA: Tôi nhặt ctimelên timevì đầu ra là đẹp hơn khi timeđược chính xác những gì tôi nên đã chọn.
El'endia Starman

Bạn biết đấy, bạn cũng có thể sắp xếp theo số lớn nhất trong thùng, bởi vì số không được phép lớn nhất sẽ luôn gấp đôi số đó.
Martin Ender

@ MartinBüttner: ...... Tôi ... uh ... Tôi không biết làm thế nào hoặc tại sao, nhưng điều đó được n=121. oO
El'endia Starman

7

Trăn 3, 121, <0,001

Cải thiện heuristic nhờ Martin Buttner có nghĩa là chúng ta thậm chí không cần sự ngẫu nhiên.

Đầu ra:

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

Mã số:

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

Trăn 3, 112

Sắp xếp theo tổng của 2 phần tử đầu tiên + xiên

[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

Tôi đã sao chép cấu trúc dữ liệu của El'endia Starman, bao gồm một danh sách các cặp, trong đó phần tử đầu tiên của cặp là các phần tử trong nhóm đó và phần thứ hai là tổng của nhóm đó.

Tôi bắt đầu với cách tiếp cận "theo dõi những khoản tiền nào có sẵn". Heuristic sắp xếp của tôi chỉ đơn giản là tổng của hai yếu tố nhỏ nhất trong một danh sách nhất định. Tôi cũng thêm một độ lệch nhỏ ngẫu nhiên để thử các khả năng khác nhau.

Mỗi lần lặp chỉ đơn giản là đặt mỗi số mới vào thùng có sẵn đầu tiên, tương tự như tham lam ngẫu nhiên. Một khi điều này không thành công, nó chỉ cần khởi động lại.

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

n = 5

seed(0)

def skew():
    return randrange(9)

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

Wow, cái này trông cực kỳ giống với mã của tôi. : P;) (Tôi không
bận

@ El'endiaStarman Tín dụng đã được thêm. Đó là một cơ sở tốt đẹp.
isaacg

7

Java 8, n = 142 144

Đầu ra cuối cùng:

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

Thực hiện tìm kiếm ngẫu nhiên có hạt được phân phối trên 4 chủ đề. Khi nó không thể tìm thấy một phân vùng phù hợp với nnó, nó sẽ cố gắng giải phóng không gian cho nmột phân vùng tại một thời điểm bằng cách đổ càng nhiều càng tốt vào các phân vùng khác.

chỉnh sửa: tinh chỉnh thuật toán để giải phóng không gian cho n, đồng thời thêm khả năng quay lại lựa chọn trước đó và chọn lại.

lưu ý: đầu ra không mang tính quyết định nghiêm ngặt vì có nhiều luồng liên quan và cuối cùng chúng có thể cập nhật thứ tốt nhất nđược tìm thấy cho đến nay theo thứ tự lộn xộn; điểm số cuối cùng là 144 là xác định và đạt được khá nhanh: 30 giây trên máy tính của tôi.

Mã là:

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, Tham lam ngẫu nhiên, n = 91

Chỉ cần cung cấp một giải pháp cơ bản, điều này lặp đi lặp lại n, theo dõi các thùng và tổng của chúng và thêm nvào một thùng ngẫu nhiên nơi nó chưa xuất hiện dưới dạng tổng. Nó chấm dứt một lần nxuất hiện trong tất cả các kkhoản tiền và nếu kết quả ntốt hơn bất kỳ nỗ lực nào trước đó, hãy in nó thành STDOUT.

Đầu vào kđược cung cấp thông qua một đối số dòng lệnh. Tối đa có thể khiện được mã hóa thành 10 vì tôi quá lười biếng thêm phân bổ bộ nhớ động, nhưng điều đó có thể được khắc phục dễ dàng.

Tôi đoán bây giờ tôi có thể đi săn một hạt giống tốt hơn, nhưng câu trả lời này có lẽ không đặc biệt cạnh tranh, vì vậy meh.

Đây là phân vùng cho 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

Và cuối cùng, đây là mã:

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

Xác nhận n=91, tìm thấy trong 138 giây. Nếu cần thiết cho việc ngắt kết nối, tôi sẽ nghỉ hưu để tránh các lỗi lớn do tải CPU khác nhau.
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;
}

Nối n tiếp theo vào tập con được chọn ngẫu nhiên. Nếu điều đó là không thể, nó sẽ loại bỏ các số ngẫu nhiên khỏi các tập hợp con và nối chúng với các số khác với hy vọng cho phép nối thêm n ở đâu đó.

Tôi đã tạo mẫu này trong awk, và vì nó có vẻ đầy hứa hẹn, tôi đã dịch nó sang C ++ để tăng tốc nó. Sử dụng một std::setthậm chí nên tăng tốc nó lên nhiều hơn.

Đầu ra cho n = 135 (sau khoảng 230 giây trên máy [cũ] của tôi)

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 95 
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 125 132 135 
3 7 8 18 20 30 32 44 49 54 63 77 82 92 104 106 116 118 128 129 133 133 

Tôi đã không kiểm tra lại tính hợp lệ, nhưng nó sẽ ổn thôi.


2

Python 3, tham lam ngẫu nhiên, n = 61

Đầu ra cuối cùng:

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

Điều này sử dụng hiệu quả thuật toán tương tự như của Martin Büttner , nhưng tôi đã phát triển nó một cách độc lập.

Có những cái kthùng có cả hai số trong đó cho đến nay và những số không thể đi trong đó nữa. Ở mỗi độ sâu trong lần lặp (về cơ bản là tìm kiếm theo chiều sâu), thứ tự bin được xáo trộn và số tiếp theo ( nextN) được đặt vào các thùng có thể lấy nó và sau đó tiến sâu hơn một bước. Nếu không có, nó trả về, sao lưu một bước.

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

Con trăn, 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, vì vậy nó không phải là một người chiến thắng, nhưng tôi cảm thấy dù sao nó cũng thuộc về nó. Tôi đã tự do không bao gồm dấu thời gian, vì nó chấm dứt ngay lập tức và vì đó không phải là một ứng cử viên thực sự.

Đầu tiên, lưu ý rằng tổng của hai số lẻ bất kỳ là số chẵn, vì vậy chúng ta có thể kết xuất tất cả các số lẻ trong khối đầu tiên. Sau đó, vì tất cả các số còn lại là số chẵn, chúng ta có thể chia chúng cho 2. Một lần nữa, chúng ta có thể ném tất cả các số lẻ kết quả trong khối thứ hai (sau khi nhân chúng lại với 2), chia các số còn lại cho 2 (nghĩa là , bằng 4 tổng thể), ném các số lẻ vào khối thứ ba (sau khi nhân chúng lại với 4), v.v ... Hoặc, để nói những từ mà các bạn hiểu, chúng tôi đặt tất cả các số có tập hợp ít quan trọng nhất bit là bit đầu tiên trong khối thứ nhất, tất cả các số có bit đặt có ý nghĩa nhỏ nhất là bit thứ hai trong khối thứ hai, v.v.

Đối với các khối k , chúng ta gặp rắc rối khi chúng ta đạt n = 2 k , vì bit thiết lập có ý nghĩa nhỏ nhất của n là bit thứ
( k + 1), không tương ứng với bất kỳ khối nào. Nói cách khác, sơ đồ này hoạt động lên
đến n = 2 k - 1. Vì vậy, trong khi với k = 5, chúng ta chỉ nhận được một ít ỏi n = 31 , con số này tăng theo cấp số nhân với k . Nó cũng thiết lập rằng S ( k ) 2 k - 1 (nhưng chúng ta thực sự có thể tìm thấy giới hạn thấp hơn tốt hơn mức đó khá dễ dàng.)

Để tham khảo, đây là kết quả cho 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]

Có một cách dễ dàng để rút ra một số phụ: di chuyển nửa trên của các số lẻ sang bất kỳ danh mục nào khác (vì tổng của chúng bị ràng buộc lớn hơn bất kỳ số nào đã có trong danh mục đó) và thêm 2 ^ k vào nửa dưới của các số lẻ. Ý tưởng tương tự có lẽ có thể được mở rộng để có được một số lg k khác, hoặc thậm chí có thể là một k khác.
Peter Taylor

@PeterTaylor Vâng, tôi nhận ra ngay sau khi đăng bài rằng điều này thực sự khá tầm thường. Nó tương đương với việc làm [1], [2,3], [4,5,6,7], ..., có lẽ đơn giản hơn, chỉ với bit đảo ngược và thứ tự khối. Thật dễ dàng để xem làm thế nào điều này có thể được mở rộng.
Ell
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.