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