#include #include "pushbox.h" #include "box-solver.h" using namespace std; mt19937 rng(random_device{}()); uniform_real_distribution d01(0, 1); uniform_int_distribution rng10(0, 9); uniform_int_distribution rngN(0, 19); #define compiler_assume(condition) \ do { \ if (!(condition)) \ __builtin_unreachable(); \ } while (false); \ const float initial_temperature = 10; const float initial_temperature_pv = 60; const float termperature_delta = .97; const int population_limit = 30; struct Gene { Maze m; int w; float T, eT; Gene() {} Gene(const Maze &m, int w, float T) : m(m), w(w), T(T) {} }; inline void expand(const Maze &q, std::vector &res, float t) { int s = Solve::solve(q); if (s != -1) res.emplace_back(q, s, t); } inline void expandAll(Maze q, std::vector &res, float t = initial_temperature) { for (int i = 0; i < POI_EXCEED; ++i) { for (int j : {0, 1}) { for (int d : {-1, 1}) { compiler_assume(q.poi[i][j] >= 0 && q.poi[i][j] < N); q.poi[i][j] += d; if (0 <= q.poi[i][j] && q.poi[i][j] < N) { bool flag = false; for (int k = 0; k < POI_EXCEED; ++k) flag |= (q.poi[i][0] == q.poi[k][0] && q.poi[i][1] == q.poi[k][1]); if (!flag) expand(q, res, t); } } } } for (int i = 0; i < 25; i++) { compiler_assume(q.isValid()); int x = rngN(rng), y = rngN(rng); q.flip(x, y); if (q.isValid()) expand(q, res, t); q.flip(x, y); } for (int i = 0; i < 4; ++i) { Maze qq = q; for (int j = 0; j < 60; ++j) { int x = rngN(rng), y = rngN(rng); qq.set(x, y, 1); } expand(qq, res, initial_temperature_pv); } for (int i = 0; i < N; i++) { for (int j = 0; j < N; j++) { int x = (rng10(rng) <= 2); if (x) q.flip(i, j); } } for (int i = 0; i < POI_EXCEED; ++i) { q.set(q.poi[i][0], q.poi[i][1], 1); } if (q.isValid()) expand(q, res, t); }; inline void writeGene(const Gene &g, std::FILE *f) { std::fprintf(f, "%d %lf\n", g.w, g.T); writeMaze(g.m, f); } inline Gene loadGene(std::FILE *f) { Gene g; std::fscanf(f, "%d %f", &g.w, &g.T); g.m = loadMaze(f); return g; } inline void writePopulation(const std::vector &p, int best_w, std::FILE *f) { std::fprintf(f, "%d %d\n", (int)p.size(), best_w); for (const auto &g : p) { writeGene(g, f); } } inline void loadPopulation(std::vector &p, int &best_w, std::FILE *f) { int pn; std::fscanf(f, "%d %d", &pn, &best_w); p.resize(pn); for (int i = 0; i < pn; ++i) { p[i] = loadGene(f); } } inline void constructMain() { std::vector population; int history_best_w; auto frecord = std::fopen("current.txt", "r"); loadPopulation(population, history_best_w, frecord); std::fclose(frecord); for (int iter_id = 1; ; ++iter_id) { std::vector nxt; for (auto &gene : population) { expandAll(gene.m, nxt, std::max(gene.T, initial_temperature)); nxt.push_back(std::move(gene)); } population.clear(); int best_w = 0, hbest_w = 0; for (const auto &gene : nxt) { best_w = std::max(best_w, gene.w); if (gene.T > initial_temperature) hbest_w = std::max(hbest_w, gene.w); } std::vector Hpopulation, Lpopulation; for (auto &gene : nxt) { const bool is_ht = gene.T > initial_temperature; const float dE = (is_ht ? hbest_w + 1 : best_w) - gene.w; gene.eT = exp(-dE / gene.T); if (gene.eT > d01(rng)) { gene.T *= termperature_delta; if (is_ht) Hpopulation.push_back(std::move(gene)); else Lpopulation.push_back(std::move(gene)); } } nxt.clear(); auto cmpET = [](const Gene &a, const Gene &b) { return a.eT > b.eT; }; if (Hpopulation.size() > population_limit) { sort(Hpopulation.begin(), Hpopulation.end(), cmpET); Hpopulation.resize(population_limit); } if (Lpopulation.size() > population_limit) { sort(Lpopulation.begin(), Lpopulation.end(), cmpET); Lpopulation.resize(population_limit); } population = std::move(Lpopulation); for (auto &g : Hpopulation) { population.push_back(std::move(g)); } Lpopulation.clear(); Hpopulation.clear(); bool broke_record = best_w > history_best_w; if (broke_record) { history_best_w = best_w; printf("New Record: %d!\n", best_w); std::FILE *f = fopen("best.txt", "w"); writePopulation(population, best_w, f); fclose(f); } if (true) { printf("Iterated for %d times.\n", iter_id); printf("Current Best=%d, History Best=%d, Population Size=%d\n" , best_w, history_best_w, (int)population.size()); std::FILE *f = fopen("current.txt", "w"); writePopulation(population, best_w, f); fclose(f); } } } int main() { constructMain(); return 0; }