최단 시간 내에이 숫자 퍼즐에 대한 모든 솔루션을 찾으십시오


16

역사

우리 회사는 회사 내 모든 사람에게 매주 뉴스 레터를 보냅니다. 이 뉴스 레터에는 수수께끼가 포함되어 있으며, 지난 주 수수께끼에 대한 솔루션을 전자 메일로 제공 한 회사의 누구에게나 외침을 들었습니다. 이 수수께끼의 대부분은 아주 사소하고 기술 회사에게는 솔직히 꽤 둔하지만, 몇 달 전에 한 가지주의를 끌었습니다.

오리지널 수수께끼 :

아래 모양이 주어진다면 :

퍼즐 이미지

자연수는 1에서 16까지입니다. 모든 연속 된 행과 연속 된 열의 합계가 29가되도록이 모양에 모두 맞 춥니 다.

예를 들어,이 퍼즐에 대한 하나의 솔루션 (뉴스 레터에 제출 한 "표준"솔루션)은 다음과 같습니다.

해결 된 퍼즐 이미지

그러나 그것을 해결하는 과정에서 다소 흥미로운 정보를 발견했습니다.

  • 그 솔루션보다 훨씬 더 많은 솔루션이 있습니다. 실제로 9,368 개의 솔루션이 있습니다.
  • 규칙 집합을 확장하여 행과 열이 서로 같을 필요가 있고 반드시 29 일 필요는없는 경우 33,608 개의 솔루션을 얻을 수 있습니다.
    • 총 27, 4,440 개의 솔루션.
    • 총 28 개 솔루션 7,400 개
    • 총 29의 솔루션 9,368 개
    • 총 30의 솔루션 6,096 개
    • 31의 합계에 대한 5,104 개의 솔루션.
    • 총 32의 솔루션 1,200 개

그래서 저와 제 동료들 (주로 제 매니저는 "일반적인 목적"프로그래밍 기술을 가진 유일한 사람 이었기 때문에 대부분의 관리자 였지만)은 한 달 동안 지속되었던 도전에 착수했습니다. 가장 빠른 방법으로 모든 단일 솔루션을 찾을 수있는 프로그램을 작성하려고 노력해야했습니다.

원래 통계

내가 문제를 해결하기 위해 작성한 첫 번째 프로그램은 단순히 무작위 솔루션을 반복해서 확인하고 솔루션을 찾았을 때 중단되었습니다. 이 문제에 대해 수학적 분석을 수행했다면, 이것이 작동하지 않았 음을 이미 알고있을 것입니다. 그러나 어떻게 든 운이 좋았으므로 단일 솔루션 (위에 게시 한 솔루션)을 찾는 데 프로그램이 1 분 밖에 걸리지 않았습니다. 프로그램의 반복 실행은 종종 10 분에서 20 분 정도 걸렸으므로 분명히이 문제에 대한 엄격한 해결책은 아니 었습니다.

퍼즐의 가능한 모든 순열을 반복하는 재귀 솔루션으로 전환하고 합산되지 않은 합계를 제거하여 많은 솔루션을 한 번에 버렸습니다. IE 내가 비교하고있는 첫 번째 행 / 열이 이미 같지 않은 경우 퍼즐에 순열 된 다른 것이 변경되지 않는다는 것을 알고 즉시 해당 지점을 확인하는 것을 중단 할 수 있습니다.

이 알고리즘을 사용하여 첫 번째 "적절한"성공을 거두었습니다. 프로그램은 약 5 분 안에 모든 33,608 개의 솔루션을 생성하고 뱉어 낼 수있었습니다.

내 관리자는 다른 접근 방식을 가졌습니다. 가능한 유일한 솔루션의 합계가 27, 28, 29, 30, 31 또는 32라는 것을 알면서도 특정 값에 대해서만 가능한 합계를 확인하는 다중 스레드 솔루션을 작성했습니다. 그는 2 분만에 프로그램을 실행할 수있었습니다. 그래서 나는 다시 반복했다. 가능한 모든 3/4 자리 합계 (프로그램 시작시; 총 런타임에서 계산)를 해시하고 행의 "부분 합계"를 사용하여 이전에 완료 된 행이 아닌 이전에 완료 된 행을 기준으로 나머지 값을 조회했습니다 나머지 모든 값을 테스트하고 시간을 72 초로 줄였습니다. 그런 다음 멀티 스레딩 로직을 사용하여 40 초로 줄였습니다. 관리자가 프로그램을 집으로 가져 가서 프로그램 실행 방식을 일부 최적화 한 후 12 초로 줄었습니다. 나는 행과 열의 평가를 재정렬했다.

한 달 후에 우리 프로그램 중 가장 빠른 것은 관리자의 경우 0.15 초, 저의 경우 0.33 초였습니다. 관리자의 프로그램은 모든 솔루션을 찾았 지만 텍스트 파일로 인쇄 하지 않았기 때문에 프로그램이 더 빠르다고 주장했습니다 . 그가이 논리를 코드에 추가했다면, 종종 0.4-0.5 초가 걸렸습니다.

우리는 개인적으로 도전 할 수 있도록 허용했지만 물론 문제는 여전히 남아 있습니다. 이 프로그램을 더 빨리 만들 수 있습니까?

그게 내가 너희들에게 제기 할 도전이다.

당신의 도전

우리가 작업 한 매개 변수는 "29의 합"규칙을 완화하여 대신 "모든 행 / 열의 합이 동일"하게하고 여러분도 그 규칙을 설정하겠습니다. 그러므로 가장 어려운 점은이 수수께끼에 대한 모든 솔루션을 가능한 짧은 시간 안에 찾아서 인쇄하는 프로그램을 작성하는 것입니다. 제출 된 솔루션에 상한선을 설정하겠습니다. 프로그램이 비교적 괜찮은 컴퓨터 (<8 세)에서 10 초 이상 걸리면 계산하기에는 너무 느릴 수 있습니다.

또한 퍼즐에 대한 몇 가지 보너스가 있습니다.

  • 솔루션을 일반화하여 16이 아닌 모든 숫자에 사용할 수 int[1,16]있습니까? 타이밍 점수는 원래 프롬프트 번호 세트를 기준으로 평가되지만이 코드 경로를 통과합니다. (-10 %)
  • 중복 번호로 정상적으로 처리하고 해결하는 방식으로 코드를 작성할 수 있습니까? 이것은 보이는 것처럼 간단하지 않습니다! "시각적으로 동일한"솔루션은 결과 집합에서 고유해야합니다. (-5 %)
  • 음수를 처리 할 수 ​​있습니까? (-5 %)

당신은 또한 수 하려고 핸들이 숫자 소수점 부동하는 솔루션을 생성 할 수 있지만,이 완전히 실패하는 경우 물론, 충격을하지 않습니다. 강력한 솔루션을 찾으면 큰 보너스 가치가 있습니다!

모든 의도와 목적을 위해 "회전"은 고유 한 솔루션으로 간주됩니다. 따라서 다른 솔루션을 순환하는 솔루션은 자체 솔루션으로 간주됩니다.

컴퓨터에서 작업하는 IDE는 Java 및 C ++입니다. 다른 언어의 답변을 수락 할 수 있지만 코드에 대해 설정하기 쉬운 런타임 환경을 얻을 수있는 링크를 제공해야 할 수도 있습니다.


3
성스러운 고양이, 좋은 첫 질문! ... 우리가 일종의 불쾌감을주는 보너스를 제외하고 (주로 코드 골프 질문에 대해서는 괜찮습니다)
cat

4
@cat 나는 보너스가 여기에 있다고 생각합니다. 내 코드에서 이러한 문제를 해결할 때 코드가 크게 느려지는 경향이 있기 때문입니다. 그래서 나는 포함을 정당화하기위한 보너스라고 생각합니다.
Xirema

2
BTW, 당신의 직업이 있습니까? 그것은 당신이 쉬운 보스와 당신의 손에 충분한 시간이있는 것처럼 들립니다 :-)
Level River St

1
중복 번호를 사용하면 두 개의 동일한 번호가 교환되는 중복 솔루션을 인쇄해도 괜찮습니까? 보너스가 어떻게 해석되는지에 대해 큰 차이를 만들 것입니다. 명확하게 설명하지만 해당 보너스를 모두 제거하는 것이 좋습니다.
Level River St

1
또한 180도 회전이 동일한 솔루션 또는 다른 솔루션으로 간주됩니까?
Level River St

답변:


7

C-약 0.5 초

이 매우 순진한 프로그램은 4 년 된 노트북에서 0.5 초 만에 모든 솔루션을 제공합니다. 다중 스레드, 해싱 없음

Windows 10, Visual Studio 2010, CPU 코어 I7 64 비트

Ideaone에서 온라인으로 사용해보십시오

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

int inuse[16];
int results[16+15+14];

FILE *fout;

int check(int number)
{
    if (number > 0 && number < 17 && !inuse[number-1])
    {
        return inuse[number-1]=1;
    }
    return 0;
}

void free(int number)
{
    inuse[number-1]=0;
}

void out(int t, int* p)
{
    int i;
    fprintf(fout, "\n%d",t);
    for(i=0; i< 16; i++) fprintf(fout, " %d",*p++);
}

void scan() 
{
    int p[16];
    int t,i;
    for (p[0]=0; p[0]++<16;) if (check(p[0]))
    {
        for (p[1]=0; p[1]++<16;) if (check(p[1]))
        {
            for (p[2]=0; p[2]++<16;) if (check(p[2]))
            {
                t = p[0]+p[1]+p[2]; // top horiz: 0,1,2
                for (p[7]=0; p[7]++<16;) if (check(p[7]))
                {
                    if (check(p[11] = t-p[7]-p[2])) // right vert: 2,7,11
                    {
                        for(p[9]=0; p[9]++<16;) if (check(p[9]))
                        {
                            for (p[10]=0; p[10]++<16;) if (check(p[10]))
                            {
                                if (check(p[12] = t-p[9]-p[10]-p[11])) // right horiz: 9,10,11,12
                                {
                                    for(p[6]=0; p[6]++<16;) if (check(p[6]))
                                    {
                                        if (check(p[15] = t-p[0]-p[6]-p[9])) // middle vert: 0,6,9,15
                                        {
                                            for(p[13]=0; p[13]++<16;) if (check(p[13]))
                                            {
                                                if (check(p[14] = t-p[13]-p[15])) // bottom horiz:  13,14,15
                                                {
                                                    for(p[4]=0; p[4]++<16;) if (check(p[4]))
                                                    {
                                                        if (check(p[8] = t-p[4]-p[13])) // left vert: 4,8,13
                                                        {
                                                            for(p[3]=0; p[3]++<16;) if (check(p[3]))
                                                            {
                                                                if (check(p[5] = t-p[3]-p[4]-p[6])) // left horiz: 3,4,5,6
                                                                {
                                                                    ++results[t];
                                                                    out(t,p);
                                                                    free(p[5]);
                                                                }
                                                                free(p[3]);
                                                            }
                                                            free(p[8]);
                                                        }
                                                        free(p[4]);
                                                    }
                                                    free(p[14]);
                                                }
                                                free(p[13]);
                                            }
                                            free(p[15]);
                                        }
                                        free(p[6]);
                                    }
                                    free(p[12]);
                                }
                                free(p[10]);
                            }
                            free(p[9]);
                        }
                        free(p[11]);
                    }
                    free(p[7]);
                }    
                free(p[2]);
            } 
            free(p[1]);
        }
        free(p[0]);
    }
    for(i=0;i<15+16+14;i++)
    {
        if(results[i]) printf("%d %d\n", i, results[i]);
    }
}

void main()
{
    clock_t begin, end;
    double time_spent;
    begin = clock();

    fout = fopen("c:\\temp\\puzzle29.txt", "w");
    scan();
    fclose(fout);

    end = clock();
    time_spent = (double)(end - begin) / CLOCKS_PER_SEC;
    printf("Time %g sec\n", time_spent);
}

성스러운 달콤한 사악한 뱀파이어 예수. 그래도 컴파일러가 정말 행복했습니다. XD
Xirema

@ edc65, 참고 int inuse[16];로 그냥 int inuse;비트로 바꾸고 비트 연산자를 사용하여 조작 할 수 있습니다. 속도 크게 올리지는 않지만 약간 도움이됩니다.
앤드류 엡스타인

@AndrewEpstein 더 느려질 수 있음-비트 시프트 vs 인덱싱
edc65

@ edc65, dumbbench 를 사용하여 원본 버전과 비트 시프트 버전을 자유롭게 테스트했습니다. 결과는 다음과 같습니다. 인덱싱 : 0.2253 +/- 5.7590e-05 비트 시프 팅 : 0.2093 +/- 6.6595e-05 따라서 약 16ms 내 컴퓨터에서 속도가 향상되었습니다. 내가 사용한 명령은 다음과 같습니다.dumbbench --precision=.01 -vvv --initial=500 ./solve
Andrew Epstein

3

C ++-300 밀리 초

요청 마다이 퍼즐을 해결하기 위해 자체 코드를 추가했습니다. 내 컴퓨터에서는 평균 0.310 초 (310 밀리 초)로 클럭되지만 차이에 따라 287 밀리 초로 빠르게 실행될 수 있습니다. 350 밀리 초 이상으로 상승하는 경우는 거의 없습니다. 일반적으로 시스템이 다른 작업으로 인해 다운 된 경우에만 가능합니다.

이 시간은 프로그램에 사용 된 자체보고를 기반으로하지만 외부 타이머를 사용하여 테스트 한 결과 비슷한 결과를 얻습니다. 프로그램의 오버 헤드는 약 10 밀리 초를 추가하는 것으로 보입니다.

또한, 내 코드는하지 않습니다 아주 제대로 중복을 처리합니다. 그것들을 사용하여 해결할 수는 있지만 솔루션 세트에서 "시각적으로 동일한"솔루션을 제거하지는 않습니다.

#include<iostream>
#include<vector>
#include<random>
#include<functional>
#include<unordered_set>
#include<unordered_map>
#include<array>
#include<thread>
#include<chrono>
#include<fstream>
#include<iomanip>
#include<string>
#include<mutex>
#include<queue>
#include<sstream>
#include<utility>
#include<atomic>
#include<algorithm>

//#define REDUCE_MEMORY_USE

typedef std::pair<int, std::vector<std::pair<int, int>>> sumlist;
typedef std::unordered_map<int, std::vector<std::pair<int, int>>> summap;
typedef std::array<int, 16> solution_space;

class static_solution_state {
public:
    std::array<int, 16> validNumbers;
    summap twosums;
    size_t padding;
    std::string spacing;

    static_solution_state(const std::array<int, 16> & _valid);

    summap gettwovaluesums();
    std::vector<sumlist> gettwovaluesumsvector();
};

static_solution_state::static_solution_state(const std::array<int, 16> & _valid) 
    : validNumbers(_valid) {
    twosums = gettwovaluesums();
    padding = 0;
    for (int i = 0; i < 16; i++) {
        size_t count = std::to_string(validNumbers[i]).size();
        if (padding <= count) padding = count + 1;
    }
    spacing.resize(padding, ' ');
}

class solution_state {
private:
    const static_solution_state * static_state;
public:
    std::array<int, 16> currentSolution;
    std::array<bool, 16> used;
    std::array<int, 7> sums;
    size_t solutions_found;
    size_t permutations_found;
    size_t level;
    std::ostream * log;

    solution_state(const static_solution_state & _sstate);
    solution_state(static_solution_state & _sstate) = delete;
    void setLog(std::ostream & out);
    const int & operator[](size_t index) const;

};

solution_state::solution_state(const static_solution_state & _sstate) {
    static_state = &_sstate;
    sums = { 0 };
    used = { false };
    currentSolution = { -1 };
    solutions_found = 0;
    permutations_found = 0;
    level = 0;
}

void solution_state::setLog(std::ostream & out) {
    log = &out;
}

const int & solution_state::operator[](size_t index) const {
    return static_state->validNumbers[currentSolution[index]];
}

int getincompletetwosum(const static_solution_state & static_state, const solution_state & state);
void permute(const static_solution_state & static_state, solution_state & state, volatile bool & reportProgress, const volatile size_t & total_tests, volatile bool & done);
void setupOutput(std::fstream & out);
void printSolution(const static_solution_state & static_state, const solution_state & state);
constexpr size_t factorial(const size_t iter);

const bool findnext2digits[16]{
    false, false, false,
    true, false,
    false, true, false,
    true, false,
    true, false,
    true, false,
    true, false
};

const int currentsum[16]{
    0, 0, 0,
    1, 1,
    2, 2, 2,
    3, 3,
    4, 4,
    5, 5,
    6, 6
};

const int twosumindexes[7][2]{
    { 0, -1},
    { 2, -1},
    { 5, -1},
    { 5, -1},
    { 0,  7},
    { 11, 4},
    { 10, 9}
};

const std::array<size_t, 17> facttable = [] {
    std::array<size_t, 17> table;
    for (int i = 0; i < 17; i++) table[i] = factorial(i);
    return table;
}();

const int adj = 1;

std::thread::id t1id;

int main(int argc, char** argv) {
    //std::ios_base::sync_with_stdio(false);
    std::array<int, 16> values = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16 };
    if (argc == 17) {
        for (int i = 0; i < 16; i++) {
            values[i] = atoi(argv[i + 1]);
        }
    }
    auto start = std::chrono::high_resolution_clock::now();
    const static_solution_state static_state(values);
#if defined(REDUCE_MEMORY_USE)
    const int num_of_threads = max(1u, min(thread::hardware_concurrency(), 16u));
#else
    const int num_of_threads = 16;
#endif
    std::vector<solution_state> states(num_of_threads, static_state);
    for (int i = 0; i < num_of_threads; i++) {
        int start = i * 16 / num_of_threads;
        states[i].permutations_found += start * factorial(16) / 16;
    }
    std::fstream out;
    setupOutput(out);
    std::locale loc("");
    std::cout.imbue(loc);
    volatile bool report = false;
    volatile bool done = false;
    volatile size_t tests = 0;

    std::thread progress([&]() {
        auto now = std::chrono::steady_clock::now();
        while (!done) {
            if (std::chrono::steady_clock::now() - now > std::chrono::seconds(1)) {
                now += std::chrono::seconds(1);

                size_t t_tests = 0;
                for (int i = 0; i < num_of_threads; i++) t_tests += states[i].permutations_found - i * factorial(16) / num_of_threads;
                tests = t_tests;
                report = true;
            }
            std::this_thread::yield();
        }
    });

    if (num_of_threads <= 1) {


        states[0].setLog(out);
        permute(static_state, states[0], report, tests, done);


    } 
    else {
        std::vector<std::thread> threads;
#if defined(REDUCE_MEMORY_USE)
        std::vector<std::fstream> logs(num_of_threads);
#else
        std::vector<std::stringstream> logs(num_of_threads);
#endif
        for (int i = 0; i < num_of_threads; i++) {
            threads.emplace_back([&, i]() {
                if (i == 0) t1id = std::this_thread::get_id();
                int start = i * 16 / num_of_threads;
                int end = (i + 1) * 16 / num_of_threads;
#if defined(REDUCE_MEMORY_USE)
                logs[i].open("T"s + to_string(i) + "log.tmp", ios::out);
#endif
                logs[i].imbue(loc);
                states[i].setLog(logs[i]);

                for (int j = start; j < end; j++) {


                    states[i].currentSolution = { j };
                    states[i].level = 1;
                    states[i].used[j] = true;
                    permute(static_state, states[i], report, tests, done);


                }
            });
        }

        std::string buffer;
        for (int i = 0; i < num_of_threads; i++) {
            threads[i].join();
#if defined(REDUCE_MEMORY_USE)
            logs[i].close();
            logs[i].open("T"s + to_string(i) + "log.tmp", ios::in);
            logs[i].seekg(0, ios::end);
            auto length = logs[i].tellg();
            logs[i].seekg(0, ios::beg);
            buffer.resize(length);
            logs[i].read(&buffer[0], length);
            logs[i].close();
            remove(("T"s + to_string(i) + "log.tmp").c_str());
            out << buffer;
#else
            out << logs[i].str();
#endif
        }
    }
    done = true;
    out.close();

    if (num_of_threads > 1) {
        size_t t_tests = 0;
        for (int i = 0; i < num_of_threads; i++) t_tests += states[i].permutations_found - i * factorial(16) / num_of_threads;
        tests = t_tests;
    }

    size_t solutions = 0;
    for (const auto & state : states) {
        solutions += state.solutions_found;
    }

    auto end = std::chrono::high_resolution_clock::now();

    progress.join();

    auto duration = end - start;
    auto secondsDuration = std::chrono::duration_cast<std::chrono::milliseconds>(duration);
    std::cout << "Total time to process all " << tests << " results: " << std::setprecision(3) << std::setiosflags(std::ostream::fixed) << (secondsDuration.count()/1000.0) << "s" << "\n";
    std::cout << "Solutions found: " << solutions << std::endl;
    //system("pause");
    return 0;
}

void permute(const static_solution_state & static_state, solution_state & state, volatile bool & reportProgress, const volatile size_t & total_tests, volatile bool & done) {
    if (done) return;
    if (state.level >= 16) {
        if (reportProgress) {
            reportProgress = false;
            std::cout << "Current Status:" << "\n";
            std::cout << "Test " << total_tests << "\n";
            std::cout << "Contents: {";
            for (int i = 0; i < 15; i++) std::cout << std::setw(static_state.padding - 1) << state[i] << ",";
            std::cout << std::setw(static_state.padding - 1) << state[15] << "}" << "(Partial Sum: " << state.sums[0] << ")" << "\n";
            std::cout << "=====================" << "\n";
        }
        printSolution(static_state,state);
        state.solutions_found++;
        state.permutations_found++;
    }
    else {
        if (state.level == 3) state.sums[0] = state[0] + state[1] + state[2];

        if (!findnext2digits[state.level]) {
            for (int i = 0; i < 16; i++) {
                if (!state.used[i]) {
                    state.currentSolution[state.level] = i;
                    state.used[i] = true;
                    state.level++;
                    permute(static_state, state, reportProgress, total_tests, done);
                    state.level--;
                    state.used[i] = false;
                }
            }
        }
        else {
            int incompletetwosum = getincompletetwosum(static_state, state);
            if (static_state.twosums.find(incompletetwosum) == static_state.twosums.end()) {
                state.permutations_found += facttable[16 - state.level];
            }
            else {
                size_t successes = 0;
                const std::vector<std::pair<int, int>> & potentialpairs = static_state.twosums.at(incompletetwosum);
                for (const std::pair<int, int> & values : potentialpairs) {
                    if (!state.used[values.first] && !state.used[values.second]) {
                        state.currentSolution[state.level] = values.first;
                        state.currentSolution[state.level + 1] = values.second;
                        state.used[values.first] = true;
                        state.used[values.second] = true;
                        state.level += 2;
                        permute(static_state, state, reportProgress, total_tests, done);
                        state.level -= 2;
                        state.used[values.first] = false;
                        state.used[values.second] = false;

                        successes++;
                    }
                }
                state.permutations_found += facttable[16 - state.level - 2] * ((16 - state.level) * (15 - state.level) - successes); 
            }
        }
    }
}

int getincompletetwosum(const static_solution_state & static_state, const solution_state & state) {
    int retvalue = state.sums[0];
    int thissum = currentsum[state.level];
    for (int i = 0; i < 2 && twosumindexes[thissum][i] >= 0; i++) {
        retvalue -= state[twosumindexes[thissum][i]];
    }
    return retvalue;
}

constexpr size_t factorial(size_t iter) {
    return (iter <= 0) ? 1 : iter * factorial(iter - 1);
}

void setupOutput(std::fstream & out) {
    out.open("puzzle.txt", std::ios::out | std::ios::trunc);
    std::locale loc("");
    out.imbue(loc);
}

void printSolution(const static_solution_state & static_state, const solution_state & state) {
    std::ostream & out = *state.log;
    out << "Test " << state.permutations_found << "\n";
    static const auto format = [](std::ostream & out, const static_solution_state & static_state, const solution_state & state, const std::vector<int> & inputs) {
        for (const int & index : inputs) {
            if (index < 0 || index >= 16) out << static_state.spacing;
            else out
                << std::setw(static_state.padding)
                << state[index];
        }
        out << "\n";
    };
    format(out, static_state, state, { -1, -1, -1,  0,  1,  2 });
    format(out, static_state, state, { 15,  9, 14, 10, -1,  3 });
    format(out, static_state, state, { -1,  8, -1, 11, 12,  4, 13 });
    format(out, static_state, state, { -1,  5,  6,  7});

    out << "Partial Sum: " << (state.sums[0]) << "\n";
    out << "=============================" << "\n";
}

summap static_solution_state::gettwovaluesums() {
    summap sums;
    for (int i = 0; i < 16; i++) {
        for (int j = 0; j < 16; j++) {
            if (i == j) continue;
            std::pair<int,int> values( i, j );
            int sum = validNumbers[values.first] + validNumbers[values.second];
            sums[sum].push_back(values);
        }
    }
    return sums;
}

std::vector<sumlist> static_solution_state::gettwovaluesumsvector() {
    std::vector<sumlist> sums;
    for (auto & key : twosums) {
        sums.push_back(key);
    }

    std::sort(sums.begin(), sums.end(), [](sumlist a, sumlist b) {
        return a.first < b.first;
    });
    return sums;
}

알고 계시 겠지만 출력을 약간 단순화하면 적절한 시간을 절약 할 수 있습니다. 다음은 코드 0.1038s +/- 0.0002 시간입니다. 간단한 출력을 사용하는 코드 시간은 다음과 같습니다. 0.0850s +/- 0.0001 따라서 적어도 내 컴퓨터에서 ~ 18ms를 절약 할 수 있습니다. 내가 사용, 밖으로 던져 이상 값으로 두 버전 모두 500 번 실행 dumbbench
앤드류 엡스타인

1

프롤로그-3 분

이런 종류의 퍼즐은 Prolog의 완벽한 사용 사례처럼 보입니다. 그래서 Prolog에서 솔루션을 코딩했습니다! 여기있어:

:- use_module(library(clpfd)).

puzzle(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15) :-
    Vars = [P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15],
    Vars ins 1..16,
    all_different(Vars),
    29 #= P0 + P1 + P2,
    29 #= P3 + P4 + P5 + P6,
    29 #= P9 + P10 + P11 + P12,
    29 #= P13 + P14 + P15,
    29 #= P0 + P6 + P9 + P15,
    29 #= P2 + P7 + P11,
    29 #= P4 + P8 + P13.

불행히도, 예상만큼 빠르지 않습니다. 선언적 프로그래밍에 더 정통한 사람 (또는 구체적으로 Prolog)은 최적화 팁을 제공 할 수 있습니다. 규칙을 호출 할 수 있습니다puzzle다음 명령으로 을 .

time(aggregate_all(count, (puzzle(P0, P1, P2, P3, P4, P5, P6, P7, P8, P9, P10, P11, P12, P13, P14, P15), labeling([leftmost, up, enum], [P9, P15, P13, P0, P4, P2, P6, P11, P1, P5, P3, P7, P14, P12, P10, P8])), Count)).

여기 에서 온라인으로 사용해보십시오 . 29코드 에서 s 대신 숫자를 대체 하여 모든 솔루션을 생성 할 수 있습니다. 약 29 초 안에 모든 29 개 솔루션이 발견되므로 가능한 모든 솔루션을 찾으려면 약 3 분이 소요됩니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.