C ++ - 300 Milisaniye
İstek üzerine, bu bulmacayı çözmek için kendi kodumu ekledim. Bilgisayarımda, ortalama 0.310 saniyede (310 milisaniye) saatler varyansa bağlı olarak, varyansa bağlı olarak 287 milisaniye kadar hızlı çalışabilir. Çok nadiren 350 milisaniyenin üzerine çıktığını görüyorum, genellikle sadece sistemim farklı bir görevle boğulmuşsa.
Bu zamanlar, programda kullanılan kendi kendine raporlamaya dayanmaktadır, ancak harici bir zamanlayıcı kullanarak test ettim ve benzer sonuçlar elde ettim. Programdaki ek yük yaklaşık 10 milisaniye ekliyor gibi görünüyor.
Ayrıca benim kod değil oldukça düzgün çiftleri işlemek. Bunları kullanarak çözebilir, ancak çözüm kümesinden "görsel olarak özdeş" çözümleri ortadan kaldırmaz.
#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;
}