합이없는 파티션 찾기


17

행정상 개요

입력이 주어지면 10 분 이내에 가능한 가장 큰 k정수 1가 없는 하위 집합 n으로 정수의 파티션을 찾으십시오 .kn

배경 : 슈어 번호

자체 합계 에 공통 요소가없는 세트 A합계A + A = { x + y | x, y in A} 가 없습니다.

모든 양의 정수 에 대해 세트 가 합이없는 서브 세트 로 분할 될 수 k있는 가장 큰 정수 가 있습니다 . 이 번호를 k 번째 Schur 번호 (OEIS A045652 )라고합니다.S(k){1, 2, ..., S(k)}k

예를 들면 다음과 같습니다 S(2) = 4. {1, 2, 3, 4}{1, 4}, {2, 3}파티션을 나눌 수 있으며 , 이는 두 개의 무 합동 서브 세트로 구성된 고유 한 파티션이지만 이제는 5어느 부분에도 추가 할 수 없습니다 .

도전

다음을 수행 하는 결정적 프로그램 을 작성하십시오 .

  • k입력 으로 양의 정수 를 취하십시오
  • 현재 Unix 타임 스탬프를 stdout에 기록
  • 파티션의 시퀀스 출력 1nk증가 합없는 집합 n현재 유닉스 타임 스탬프와 각 시퀀스에 따라.

승자는 n입력이 주어지면 내 컴퓨터에서 10 분 이내에 가장 큰 파티션을 인쇄하는 프로그램이 될 것 5입니다. 동점은 가장 빠른 시간으로 n세 번 이상 실행 되는 최대의 파티션을 찾는 데 시간이 걸리므로 출력에 타임 스탬프가 포함되어야합니다.

중요한 세부 사항 :

  • Ubuntu Precise가 있으므로 언어가 지원되지 않으면 점수를 매길 수 없습니다.
  • Intel Core2 Quad CPU가 있으므로 멀티 스레딩을 사용하려면 4 개 이상의 스레드를 사용하는 것이 중요하지 않습니다.
  • 특정 컴파일러 플래그 또는 구현을 사용하려면 응답에 명확하게 문서화하십시오.
  • 입력을 처리하기 위해 코드를 특수하게 표현해서는 안됩니다 5.
  • 찾은 모든 개선 사항을 출력 할 필요는 없습니다. 예를 들어 입력의 2경우 파티션 만 출력 할 수 n = 4있습니다. 그러나 처음 10 분 동안 아무것도 출력하지 않으면 점수를로 계산 n = 0합니다.

답변:


8

정렬 가장 많은 파이썬 3, N = 92 121

최대 n도달 범위 를 예기치 않게 개선 한 제안에 대해 Martin Büttner에게 감사드립니다 .

마지막 출력 :

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

알고리즘은 아래 인용 된 이전 답변과 동일합니다.

지금까지 숫자와 더 이상 들어갈 수없는 숫자가 모두있는 k 개의 쓰레기통이 있습니다. 반복의 각 깊이 (기본적으로 깊이 우선 검색)에서 빈 순서가 섞이고 다음 번호 (nextN)가 (순차적으로) 빈에 들어간 다음 한 단계 더 깊이 이동합니다. 없는 경우 한 단계 백업하여 돌아갑니다.

... 단 하나의 예외가 있습니다 : 출력 함 순서가 섞이지 않습니다 . 대신 가장 많은 수 의 용지함 이 먼저 나오는 방식으로 정렬 됩니다 . 이것은 8 초 만에 도달했습니다 !n = 121

암호:

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

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

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

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

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

            search(k, nextN2, sets2)

search(5)

참고 : 허용되지 않는 숫자 범위 내에서 허용되는 수의 최대 개수를 기준으로 n=59정렬하고 nextN제공하는 것보다 적은 수의 허용 된 번호를 기준으로 정렬 합니다 n=64. 허용되지 않는 숫자 목록의 길이 (반복 될 수 있음)를 기준으로 정렬하면 매우 빠르게 우아한 n=30패턴이됩니다.
El'endia Starman

출력 시간 형식이 정확하지 않습니다 (신기원 이후 몇 초가되어야하지만 볼 수 있습니다 Tue Nov 10 00:44:25 2015) n=92.2 초 안에 보았습니다 .
피터 테일러

아, 시간 형식이 정확히 걸린 시간을 보여주는 것만 큼 중요하지 않다는 것을 알았습니다. 나는 그것을 알아 내고 그것을 바꿀 것이다. 편집 : 도우. 나는 집어 ctime이상 time시 출력이 예뻐 때문에 time내가 골랐다해야 정확히 무엇인지.
El'endia Starman 1

허용되지 않는 가장 큰 숫자는 항상 두 배이므로 bin에서 가장 큰 숫자로 정렬 할 수도 있습니다.
Martin Ender

@ MartinBüttner : ...... 나는 ... 어 ... 어떻게 왜 그런지 모르겠지만, 그 결과는 n=121. oO
El'endia Starman 8:10에

7

파이썬 3, 121, <0.001

Martin Buttner 덕분에 휴리스틱이 향상되어 임의성이 필요하지 않습니다.

산출:

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

암호:

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

n = 5

seed(0)

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

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

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

search()

파이썬 3, 112

처음 2 개 요소 + 기울이기의 합계로 정렬

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

El'endia Starman의 데이터 구조를 복사했습니다. 쌍의 첫 번째 요소는 해당 버킷의 요소이고 두 번째는 해당 버킷의 합계입니다.

나는 같은 "사용할 수있는 합계 추적"접근 방식으로 시작합니다. 내 정렬 휴리스틱은 단순히 주어진 목록에서 가장 작은 두 요소의 합계입니다. 또한 다른 가능성을 시도하기 위해 작은 임의의 왜곡을 추가합니다.

각 반복은 단순히 임의의 욕심과 유사하게 각각의 새로운 숫자를 첫 번째 사용 가능한 빈에 넣습니다. 이것이 실패하면 단순히 다시 시작됩니다.

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

n = 5

seed(0)

def skew():
    return randrange(9)

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

와우, 이것은 내 코드와 매우 유사합니다. : P;) (나는 전혀 신경 쓰지 않는다.)
El'endia Starman 11:10

@ El'endiaStarman Credit이 추가되었습니다. 좋은 기초입니다.
isaacg

7

자바 8, N = 142 144

마지막 출력 :

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

4 개 스레드에 분산 된 시드 임의 검색을 수행합니다. 적합한 파티션을 찾을 수 없으면 다른 파티션으로 최대한 많이 덤프하여 한 번에 한 파티션의 n공간을 확보하려고 n합니다.

편집 :에 대한 공간을 확보하기위한 알고리즘을 조정하고 n이전 선택으로 돌아가 다시 선택할 수있는 기능을 추가했습니다.

참고 : 여러 스레드가 관련되어 있기 때문에 출력이 결정 적으로 결정되지는 않았으며 n지금까지 발견 된 최상의 결과를 뒤죽박죽 순서로 업데이트 할 수 있습니다 . 144의 최종 점수는 결정 론적이며 상당히 빨리 도달합니다. 내 컴퓨터에서 30 초입니다.

코드는 다음과 같습니다

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

public class SumFree {

    private static int best;

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

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

        System.out.println(start);

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

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

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

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

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

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

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

                            Partition other = partitions.get(i);

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        Partition() {
        }

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

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

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

5

C, 랜덤 탐욕, n = 91

기준 솔루션을 제공하기 위해이 과정을 반복 n하여 빈과 해당 합계를 추적하고 n아직 합계로 표시되지 않는 임의의 빈에 추가 합니다. n모든 k합계에 한 번 나타나고 결과 n가 이전 시도보다 낫다면 STDOUT에 인쇄합니다.

입력 k은 명령 행 인수를 통해 제공됩니다. k동적 메모리 할당이 너무 게으 르기 때문에 가능한 최대 값 은 현재 10으로 하드 코딩되어 있지만 쉽게 수정할 수 있습니다.

나는 지금 더 나은 종자를 찾기 위해 갈 수있을 것 같지만이 대답은 어쨌든 특별히 경쟁적이지 않을 것입니다.

파티션은 다음과 같습니다 n = 91.

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

마지막으로 코드는 다음과 같습니다.

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

#define MAX_K 10
#define MAX_N 1024

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

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

    int k = atoi(argv[1]);

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

    int best = 0;

    srand(1447101176);

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

            if (!available_bins) break;

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

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

            ++n;
        }

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

    return 0;
}

n=91138 초 안에 확인 되었습니다. 타이 브레이킹에 필요한 경우 다른 CPU로드로 인한 큰 오류를 피하기 위해 시간을 다시 지정합니다.
피터 테일러

3

C ++, 135

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


using namespace std;

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

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

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

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

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

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

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

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

            if(c<0) --n;

            t=n;

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

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

            last=c;

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

            }

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

        cnt=0;

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

    return 0;
}

다음 n을 무작위로 선택된 서브 세트에 추가합니다. 이것이 가능하지 않은 경우, 서브 세트에서 난수를 제거하고 어딘가에 n을 추가 할 수 있도록하기 위해 다른 숫자를 추가합니다.

나는 이것을 awk로 프로토 타입 화했고, 유망 해 보였기 때문에 속도를 높이기 위해 C ++로 번역했다. 를 사용하면 std::set속도가 더 빨라집니다.

n = 135에 대한 출력 ([이전] 시스템에서 약 230 초 후)

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

나는 유효성을 다시 확인하지는 않았지만 괜찮습니다.


2

파이썬 3, 랜덤 욕심, n = 61

마지막 출력 :

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

이것은 Martin Büttner 와 동일한 알고리즘을 효과적으로 사용 하지만 독립적으로 개발했습니다.

있다 k, 지금까지의 숫자를 모두가 쓰레기통과 더 이상 갈 수없는 숫자. 반복의 각 깊이 (기본적으로 깊이 우선 검색)에서 빈 순서가 섞이고 다음 숫자 ( nextN)가 (순차적으로)이를 수용 할 수있는 빈에 넣은 다음 한 단계 더 깊게 이동합니다. 없는 경우 한 단계 씩 백업하여 돌아갑니다.

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

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

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

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

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

            search(k, nextN2, sets2)

search(5)

2

파이썬, n = 31

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

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

네, 당연히 승자는 아니지만, 어쨌든 여기에 속한다고 느꼈습니다. 타임 스탬프를 포함하지 않는 자유를 가져 왔습니다. 순간적으로 끝나기 때문에 실제 경쟁자가 아니기 때문입니다.

먼저 두 홀수의 합은 짝수이므로 첫 번째 블록에서 모든 홀수를 덤프 할 수 있습니다. 그런 다음 나머지 숫자가 모두 짝수이므로 숫자를 2로 나눌 수 있습니다. 다시 한 번, 두 번째 블록에 모든 결과 홀수를 던지고 (2를 다시 곱한 후) 나머지 숫자를 2로 나눕니다 (예 : , 전체적으로 4로), 세 번째 블록에 홀수를 던지고 (4를 다시 곱한 후) 등등 ... 또는 여러분이 이해하는 단어를 넣으려면 가장 중요하지 않은 세트의 모든 숫자를 넣습니다 비트는 첫 번째 블록의 첫 번째 비트이며, 최하위 설정 비트가 두 번째 블록의 두 번째 비트 인 모든 숫자 등입니다.

들면 유전율 우리가 도달하면 블록, 우리는 문제로 실행 N = 2 (k)를 의 최하위 설정된 비트 이후, n은
제 ( K 임의의 블록에 대응하지 않는 + 1) 번째 비트. 즉,이 방식은 최대 작동
N = 2 K 에 대한 반면, 1 그래서 - K = 5 우리는 단지 빈약 얻을 N = 31 이 숫자는 기하 급수적으로 증가, K . 또한 S ( k ) ≥ 2 k -1으로 설정합니다 (그러나 실제로는 그보다 훨씬 더 낮은 하한값을 찾을 수 있습니다).

참고로 다음은 k = 5에 대한 결과입니다 .

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

여분의 것을 짜내는 쉬운 방법이 있습니다 : 홀수의 상반부를 다른 카테고리로 옮기고 (그 합계가 이미 해당 카테고리에있는 숫자보다 더 크므로) 2 ^ k를 하단에 추가하십시오 홀수. 같은 아이디어는 다른 lg k 숫자 또는 다른 k를 얻기 위해 확장 될 수 있습니다.
피터 테일러

@PeterTaylor 그래, 나는 이것이 실제로 아주 사소한 것을 게시 한 후 짧게 깨달았다. [1], [2,3], [4,5,6,7], ...역 비트와 블록 순서 를 사용하는 것보다 간단합니다. 이 확장 방법을 쉽게 알 수 있습니다.
Ell
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.