Compare commits
2 Commits
4690eb2082
...
c21feb5d9a
Author | SHA1 | Date | |
---|---|---|---|
c21feb5d9a | |||
584628967d |
@ -163,8 +163,8 @@ inline int solve(Maze q) {
|
||||
}; // namespace Solve
|
||||
|
||||
const float initial_temperature = 10;
|
||||
const float initial_temperature_pv = 70;
|
||||
const float termperature_delta = .98;
|
||||
const float initial_temperature_pv = 60;
|
||||
const float termperature_delta = .97;
|
||||
const int population_limit = 30;
|
||||
|
||||
struct Gene {
|
||||
@ -186,11 +186,14 @@ inline void expandAll(Maze q, std::vector<Gene> &res, float t = initial_temperat
|
||||
for (int j : {0, 1}) {
|
||||
for (int d : {-1, 1}) {
|
||||
compiler_assume(q.poi[i][j] >= 0 && q.poi[i][j] < N);
|
||||
int z = q.poi[i][j] + d;
|
||||
if (0 <= z && z < N) {
|
||||
q.poi[i][j] += d;
|
||||
expand(q, res, t);
|
||||
q.poi[i][j] -= d;
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
359
optimizer/box-eater.cpp
Normal file
359
optimizer/box-eater.cpp
Normal file
@ -0,0 +1,359 @@
|
||||
#include <bits/stdc++.h>
|
||||
#include "pushbox.h"
|
||||
#include "box-solver.h"
|
||||
|
||||
std::mt19937 rng(std::random_device{}());
|
||||
|
||||
#define compiler_assume(condition) \
|
||||
do { \
|
||||
if (!(condition)) \
|
||||
__builtin_unreachable(); \
|
||||
} while (false); \
|
||||
|
||||
const float temperature_initial = 60;
|
||||
const float temperature_low = 10;
|
||||
const float temperature_delta = .97;
|
||||
const int species_limit = 5;
|
||||
const int population_limit = 10;
|
||||
const int SPECIES_NAME_LEN = 4;
|
||||
|
||||
struct Gene {
|
||||
Maze m;
|
||||
int w;
|
||||
Gene() {}
|
||||
Gene(const Maze &m, int w) : m(m), w(w) {}
|
||||
};
|
||||
|
||||
struct Species {
|
||||
std::vector<Gene> population;
|
||||
int best_w;
|
||||
float T, eT;
|
||||
char name[SPECIES_NAME_LEN + 1];
|
||||
int age, tactic;
|
||||
|
||||
Species() : population(), best_w(-1), T(1.), eT(-1), name{"NULL"}, age(0) {}
|
||||
|
||||
int size() const {
|
||||
return population.size();
|
||||
}
|
||||
|
||||
bool empty() const {
|
||||
return population.empty();
|
||||
}
|
||||
|
||||
bool operator<(const Species &o) const {
|
||||
return eT < o.eT;
|
||||
}
|
||||
};
|
||||
|
||||
inline void writeGene(const Gene &g, std::FILE *f) {
|
||||
std::fprintf(f, "%d\n", g.w);
|
||||
writeMaze(g.m, f);
|
||||
}
|
||||
|
||||
inline Gene loadGene(std::FILE *f) {
|
||||
Gene g;
|
||||
std::fscanf(f, "%d", &g.w);
|
||||
g.m = loadMaze(f);
|
||||
return g;
|
||||
}
|
||||
|
||||
inline void writeSpecies(const Species &s, std::FILE *f) {
|
||||
std::fprintf(f, "%d %d %.12f %s %d %d\n", s.size(), s.best_w, s.T, s.name, s.age, s.tactic);
|
||||
for (const auto &g : s.population) {
|
||||
writeGene(g, f);
|
||||
}
|
||||
}
|
||||
|
||||
inline Species loadSpecies(std::FILE *f) {
|
||||
Species res;
|
||||
int n;
|
||||
std::fscanf(f, "%d %d %f %s %d %d", &n, &res.best_w, &res.T, res.name, &res.age, &res.tactic);
|
||||
res.population.reserve(n);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
res.population.push_back(loadGene(f));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void loadBiosphere(std::vector<Species> &species, int &best_w, std::FILE *f) {
|
||||
int n;
|
||||
std::fscanf(f, "%d %d", &n, &best_w);
|
||||
species.reserve(n);
|
||||
for (int i = 0; i < n; ++i)
|
||||
species.push_back(loadSpecies(f));
|
||||
}
|
||||
|
||||
inline void writeBiosphere(const std::vector<Species> &species, int &best_w, std::FILE *f) {
|
||||
int n = species.size();
|
||||
std::fprintf(f, "%d %d\n", n, best_w);
|
||||
for (int i = 0; i < n; ++i)
|
||||
writeSpecies(species[i], f);
|
||||
}
|
||||
|
||||
inline void randomName(int n, char res[]) {
|
||||
static std::uniform_int_distribution<int> ld(0, 35);
|
||||
for (int i = 0; i < n; ++i) {
|
||||
int c = ld(rng);
|
||||
res[i] = (c < 26 ? c + 'a' : c - 26 + '0');
|
||||
}
|
||||
}
|
||||
|
||||
static std::uniform_int_distribution<int> rng0N(0, N - 1);
|
||||
|
||||
inline void mutationRandomHole(Species &res, const Gene &sc, int clear_cnt) {
|
||||
Gene ac = sc;
|
||||
for (int i = 0; i < clear_cnt; ++i) {
|
||||
int x = rng0N(rng), y = rng0N(rng);
|
||||
ac.m.set(x, y, SQR_SPACE);
|
||||
}
|
||||
|
||||
ac.w = Solve::solve(ac.m);
|
||||
res.best_w = ac.w;
|
||||
res.population.push_back(std::move(ac));
|
||||
}
|
||||
|
||||
inline void mutationReselectPOI(Species &res, const Gene &sc) {
|
||||
Gene ac = sc;
|
||||
for (int i = 0; i < POI_EXCEED; ++i) {
|
||||
int x = rng0N(rng), y = rng0N(rng);
|
||||
while (true) {
|
||||
bool flag = false;
|
||||
for (int j = 0; j < POI_EXCEED; ++j)
|
||||
flag |= (x == ac.m.poi[j][0] && y == ac.m.poi[j][1]);
|
||||
|
||||
if (!flag)
|
||||
break;
|
||||
x = rng0N(rng);
|
||||
y = rng0N(rng);
|
||||
}
|
||||
|
||||
ac.m.poi[i][0] = x;
|
||||
ac.m.poi[i][1] = y;
|
||||
for (int dx = -1; dx <= 1; ++dx) {
|
||||
for (int dy = -1; dy <= 1; ++dy) {
|
||||
int xx = x + dx, yy = y + dy;
|
||||
if (0 <= xx && xx < N && 0 <= yy && yy < N)
|
||||
ac.m.set(xx, yy, SQR_SPACE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ac.w = Solve::solve(ac.m);
|
||||
if (ac.w != -1) {
|
||||
res.best_w = ac.w;
|
||||
res.population.push_back(std::move(ac));
|
||||
}
|
||||
}
|
||||
|
||||
inline void mutationLineCl(Species &res, const Gene &sc) {
|
||||
Gene ac = sc;
|
||||
int r = rng0N(rng);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
ac.m.set(r, i, SQR_SPACE);
|
||||
}
|
||||
|
||||
ac.w = Solve::solve(ac.m);
|
||||
res.best_w = ac.w;
|
||||
res.population.push_back(std::move(ac));
|
||||
}
|
||||
|
||||
inline void mutationColCl(Species &res, const Gene &sc) {
|
||||
Gene ac = sc;
|
||||
int c = rng0N(rng);
|
||||
for (int i = 0; i < N; ++i) {
|
||||
ac.m.set(i, c, SQR_SPACE);
|
||||
}
|
||||
|
||||
ac.w = Solve::solve(ac.m);
|
||||
res.best_w = ac.w;
|
||||
res.population.push_back(std::move(ac));
|
||||
}
|
||||
|
||||
inline void mutationSqrCl(Species &res, const Gene &sc, int sz) {
|
||||
Gene ac = sc;
|
||||
int cx = rng0N(rng), cy = rng0N(rng);
|
||||
int sz2 = sz / 2;
|
||||
for (int dx = -sz2; dx <= sz2; ++dx) {
|
||||
for (int dy = -sz2; dy <= sz2; ++dy) {
|
||||
int xx = cx + dx, yy = cy + dy;
|
||||
if (0 <= xx && xx < N && 0 <= yy && yy < N)
|
||||
ac.m.set(xx, yy, SQR_SPACE);
|
||||
}
|
||||
}
|
||||
|
||||
ac.w = Solve::solve(ac.m);
|
||||
res.best_w = ac.w;
|
||||
res.population.push_back(std::move(ac));
|
||||
}
|
||||
|
||||
inline Species mutation(const Species &sc) {
|
||||
static std::uniform_int_distribution<int> rngTacs(0, 6);
|
||||
Species res;
|
||||
randomName(SPECIES_NAME_LEN, res.name);
|
||||
res.T = temperature_initial;
|
||||
|
||||
do {
|
||||
int tactic = rngTacs(rng);
|
||||
res.tactic = tactic;
|
||||
switch (tactic) {
|
||||
case 0:
|
||||
mutationRandomHole(res, sc.population[0], 60);
|
||||
break;
|
||||
case 1:
|
||||
mutationRandomHole(res, sc.population[0], 40);
|
||||
break;
|
||||
case 2:
|
||||
mutationReselectPOI(res, sc.population[0]);
|
||||
break;
|
||||
case 3:
|
||||
mutationLineCl(res, sc.population[0]);
|
||||
break;
|
||||
case 4:
|
||||
mutationColCl(res, sc.population[0]);
|
||||
break;
|
||||
case 5:
|
||||
mutationSqrCl(res, sc.population[0], 3);
|
||||
mutationSqrCl(res, sc.population[0], 3);
|
||||
break;
|
||||
case 6:
|
||||
mutationSqrCl(res, sc.population[0], 5);
|
||||
break;
|
||||
}
|
||||
} while (res.size() == 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void expand(const Maze &q, std::vector<Gene> &res) {
|
||||
int s = Solve::solve(q);
|
||||
if (s != -1)
|
||||
res.emplace_back(q, s);
|
||||
}
|
||||
|
||||
inline void inheritGene(Maze q, std::vector<Gene> &res) {
|
||||
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);
|
||||
}
|
||||
q.poi[i][j] -= d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 25; i++) {
|
||||
compiler_assume(q.isValid());
|
||||
int x = rng0N(rng), y = rng0N(rng);
|
||||
q.flip(x, y);
|
||||
if (q.isValid())
|
||||
expand(q, res);
|
||||
q.flip(x, y);
|
||||
}
|
||||
}
|
||||
|
||||
inline void inherit(Species &s) {
|
||||
std::vector<Gene> nxt;
|
||||
for (auto &g : s.population) {
|
||||
inheritGene(g.m, nxt);
|
||||
nxt.push_back(std::move(g));
|
||||
}
|
||||
s.population.clear();
|
||||
|
||||
for (const auto &g : nxt) {
|
||||
s.best_w = std::max(s.best_w, g.w);
|
||||
}
|
||||
|
||||
for (auto &g : nxt) {
|
||||
if (g.w == s.best_w)
|
||||
s.population.push_back(std::move(g));
|
||||
}
|
||||
nxt.clear();
|
||||
|
||||
std::shuffle(s.population.begin(), s.population.end(), rng);
|
||||
if (s.population.size() > population_limit)
|
||||
s.population.resize(population_limit);
|
||||
}
|
||||
|
||||
int main() {
|
||||
std::vector<Species> biosphere;
|
||||
int history_best_w;
|
||||
|
||||
auto frecord = std::fopen("current.txt", "r");
|
||||
loadBiosphere(biosphere, history_best_w, frecord);
|
||||
std::fclose(frecord);
|
||||
|
||||
std::uniform_real_distribution<float> d01(0, 1);
|
||||
for (int iter_id = 1; ; ++iter_id) {
|
||||
int best_w = 0, hbest_w = 0;
|
||||
for (auto &s : biosphere) {
|
||||
inherit(s);
|
||||
best_w = std::max(best_w, s.best_w);
|
||||
if (s.T > temperature_low)
|
||||
hbest_w = std::max(hbest_w, s.best_w);
|
||||
}
|
||||
|
||||
std::vector<Species> Hnxt, Lnxt;
|
||||
for (auto &s : biosphere) {
|
||||
const bool is_ht = s.T > temperature_low;
|
||||
const float dE = (is_ht ? hbest_w : best_w) - s.best_w;
|
||||
s.eT = exp(-dE / s.T);
|
||||
if (s.eT >= d01(rng) || s.age <= 15) {
|
||||
if (is_ht)
|
||||
Hnxt.push_back(std::move(s));
|
||||
else
|
||||
Lnxt.push_back(std::move(s));
|
||||
}
|
||||
}
|
||||
biosphere.clear();
|
||||
if (Lnxt.size()) {
|
||||
biosphere.push_back(std::move(*std::max_element(Lnxt.begin(), Lnxt.end())));
|
||||
}
|
||||
|
||||
while (Hnxt.size() + biosphere.size() < species_limit) {
|
||||
if (biosphere.size()) {
|
||||
Hnxt.push_back(mutation(biosphere[0]));
|
||||
} else {
|
||||
int sc = std::uniform_int_distribution<int>{0, (int)Hnxt.size() - 1}(rng);
|
||||
Hnxt.push_back(mutation(Hnxt[sc]));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto &s : Hnxt) {
|
||||
s.age += 1;
|
||||
s.T = std::max(s.T * temperature_delta, temperature_low);
|
||||
biosphere.push_back(std::move(s));
|
||||
}
|
||||
Hnxt.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");
|
||||
writeBiosphere(biosphere, best_w, f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
if (true) {
|
||||
printf("Iterated for %d times.\n", iter_id);
|
||||
printf("Current Best=%d, History Best=%d, Species:\n", best_w, history_best_w);
|
||||
for (auto &s : biosphere) {
|
||||
printf(" - %s[%d]: best=%d T=%.3f age=%d.\n", s.name, s.tactic, s.best_w, s.T, s.age);
|
||||
}
|
||||
|
||||
std::FILE *f = fopen("current.txt", "w");
|
||||
writeBiosphere(biosphere, best_w, f);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
72
optimizer/box-solver.h
Normal file
72
optimizer/box-solver.h
Normal file
@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
#include <queue>
|
||||
#include <tuple>
|
||||
#include <cstring>
|
||||
#include "pushbox.h"
|
||||
|
||||
namespace Solve {
|
||||
std::bitset<N> mp[N];
|
||||
int dis[N][N][N][N];
|
||||
std::queue<std::tuple<int, int, int, int>> qu;
|
||||
|
||||
inline int bfs(int px, int py, int bx, int by, int tx, int ty) {
|
||||
std::memset(dis, 127, sizeof(dis));
|
||||
while (!qu.empty())
|
||||
qu.pop();
|
||||
|
||||
auto expand = [&](int npx, int npy, int nbx, int nby, int d) {
|
||||
if (npx < 0 || npx >= N)
|
||||
return;
|
||||
if (npy < 0 || npy >= N)
|
||||
return;
|
||||
if (nbx < 0 || nbx >= N)
|
||||
return;
|
||||
if (nby < 0 || nby >= N)
|
||||
return;
|
||||
if (mp[npx][npy] == 0)
|
||||
return;
|
||||
if (mp[nbx][nby] == 0)
|
||||
return;
|
||||
if (npx == nbx && npy == nby)
|
||||
return;
|
||||
|
||||
if (dis[npx][npy][nbx][nby] <= d)
|
||||
return;
|
||||
dis[npx][npy][nbx][nby] = d;
|
||||
qu.emplace(npx, npy, nbx, nby);
|
||||
};
|
||||
|
||||
expand(px, py, bx, by, 0);
|
||||
|
||||
while (!qu.empty()) {
|
||||
auto [npx, npy, nbx, nby] = qu.front();
|
||||
int d = dis[npx][npy][nbx][nby];
|
||||
qu.pop();
|
||||
|
||||
if (nbx == tx && nby == ty)
|
||||
return d;
|
||||
|
||||
expand(npx + 1, npy, nbx, nby, d + 1);
|
||||
expand(npx - 1, npy, nbx, nby, d + 1);
|
||||
expand(npx, npy + 1, nbx, nby, d + 1);
|
||||
expand(npx, npy - 1, nbx, nby, d + 1);
|
||||
if (npx + 1 == nbx && npy == nby)
|
||||
expand(npx + 1, npy, nbx + 1, nby, d + 1);
|
||||
if (npx - 1 == nbx && npy == nby)
|
||||
expand(npx - 1, npy, nbx - 1, nby, d + 1);
|
||||
if (npx == nbx && npy + 1 == nby)
|
||||
expand(npx, npy + 1, nbx, nby + 1, d + 1);
|
||||
if (npx == nbx && npy - 1 == nby)
|
||||
expand(npx, npy - 1, nbx, nby - 1, d + 1);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
inline int solve(Maze q) {
|
||||
for (int i = 0; i < 20; ++i)
|
||||
mp[i] = q.M[i];
|
||||
return bfs(q.poi[POI_PERSON][0], q.poi[POI_PERSON][1]
|
||||
, q.poi[POI_BOX][0], q.poi[POI_BOX][1], q.poi[POI_TARGET][0], q.poi[POI_TARGET][1]);
|
||||
}
|
||||
}; // namespace Solve
|
92
optimizer/pushbox.h
Normal file
92
optimizer/pushbox.h
Normal file
@ -0,0 +1,92 @@
|
||||
#pragma once
|
||||
#include <bitset>
|
||||
|
||||
const int N = 20;
|
||||
|
||||
enum {
|
||||
POI_PERSON,
|
||||
POI_BOX,
|
||||
POI_TARGET,
|
||||
POI_EXCEED,
|
||||
};
|
||||
|
||||
enum {
|
||||
SQR_WALL = 0,
|
||||
SQR_SPACE = 1,
|
||||
SQR_EXCEED = 2,
|
||||
};
|
||||
|
||||
struct Maze {
|
||||
std::bitset<N> M[N];
|
||||
int poi[3][2];
|
||||
|
||||
int at(int x, int y) const {
|
||||
return M[x][y];
|
||||
}
|
||||
|
||||
void set(int x, int y, int v) {
|
||||
M[x][y] = v;
|
||||
}
|
||||
|
||||
void flip(int x, int y) {
|
||||
M[x].flip(y);
|
||||
}
|
||||
|
||||
bool isValid() const {
|
||||
for (int i = 0; i < POI_EXCEED; ++i) {
|
||||
for (int j : {0, 1}) {
|
||||
if (poi[i][j] < 0 || poi[i][j] >= N)
|
||||
return false;
|
||||
}
|
||||
|
||||
if (at(poi[i][0], poi[i][1]) == 0)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
inline Maze loadMaze(std::FILE *f) {
|
||||
char *s = new char[N + 5];
|
||||
Maze res;
|
||||
for (int i = 0; i < N; ++i) {
|
||||
std::fscanf(f, "%s", s);
|
||||
for (int j = 0; j < N; ++j) {
|
||||
res.set(i, j, s[j] != '#');
|
||||
switch (s[j]) {
|
||||
case 'P':
|
||||
res.poi[POI_PERSON][0] = i;
|
||||
res.poi[POI_PERSON][1] = j;
|
||||
break;
|
||||
case '*':
|
||||
res.poi[POI_BOX][0] = i;
|
||||
res.poi[POI_BOX][1] = j;
|
||||
break;
|
||||
case 'O':
|
||||
res.poi[POI_TARGET][0] = i;
|
||||
res.poi[POI_TARGET][1] = j;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
delete[] s;
|
||||
return res;
|
||||
}
|
||||
|
||||
inline void writeMaze(const Maze &m, std::FILE *f) {
|
||||
for (int i = 0; i < N; ++i) {
|
||||
for (int j = 0; j < N; ++j) {
|
||||
if (i == m.poi[POI_PERSON][0] && j == m.poi[POI_PERSON][1])
|
||||
std::fputc('P', f);
|
||||
else if (i == m.poi[POI_BOX][0] && j == m.poi[POI_BOX][1])
|
||||
std::fputc('*', f);
|
||||
else if (i == m.poi[POI_TARGET][0] && j == m.poi[POI_TARGET][1])
|
||||
std::fputc('O', f);
|
||||
else if (m.at(i, j) == 0)
|
||||
std::fputc('#', f);
|
||||
else
|
||||
std::fputc('.', f);
|
||||
}
|
||||
std::fputc('\n', f);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user