Last active
February 1, 2018 03:32
-
-
Save hakomo/23c07ab9b823324a5ef6e6581a7fa6b3 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <algorithm> | |
#include <cmath> | |
#include <functional> | |
#include <iostream> | |
#include <vector> | |
using namespace std; | |
#define U(v) cerr << #v << ": " << (v) << endl | |
double getTime() { | |
unsigned long long a, d; | |
__asm__ volatile ("rdtsc" : "=a" (a), "=d" (d)); | |
return (d << 32 | a) / 2.8e9; | |
} | |
int rando(int b) { | |
static unsigned y = 2463534242; | |
y ^= (y ^= (y ^= y << 13) >> 17) << 5; | |
return y % b; | |
} | |
int N; | |
double sint[400]; | |
double diffs[200]; | |
double transitionTh[256]; | |
vector<pair<int, int>> edges; | |
vector<unsigned char> valueToValues[200]; | |
double valueToScore[200]; | |
int valueToIndex[200]; | |
int indexToValue[200]; | |
int bestIndexToValue[200]; | |
int rangei[100]; | |
int ranget[100][200]; | |
void init() { | |
for (int i = 0; i < N; ++i) | |
valueToIndex[indexToValue[i]] = i; | |
fill_n(valueToScore, N, 0); | |
for (int v = 0; v < N; ++v) | |
for (unsigned char w : valueToValues[v]) | |
valueToScore[v] += sint[valueToIndex[w] - valueToIndex[v] + 200]; | |
random_shuffle(edges.begin(), edges.end(), rando); | |
for (int d = 1; d < N / 2; ++d) | |
random_shuffle(ranget[d], ranget[d] + d * 2, rando); | |
} | |
double eval() { | |
double score = 0; | |
for (int i = 0; i < N; ++i) | |
for (int j : valueToValues[i]) | |
score += sint[valueToIndex[i] - valueToIndex[j] + 200]; | |
return score / 2; | |
} | |
struct PointsOnTheCircle { | |
vector<int> permute(const vector<int>& matrix) const { | |
double startTime = getTime(); | |
N = (int)sqrt(matrix.size()); | |
{ | |
double pi = atan(1) * 4; | |
for (int i = 1; i < N; ++i) | |
sint[200 + i] = sint[200 - i] = sin(pi / N * i); | |
for (int i = 1; i < N; ++i) | |
diffs[i] = sin(pi / N * (i + 1)) - sin(pi / N * i); | |
} | |
for (int d = 1; d < N / 2; ++d) { | |
int i = 0; | |
for (int e = 1; e <= d; ++e) { | |
ranget[d][i++] = e; | |
ranget[d][i++] = -e; | |
} | |
} | |
for (int y = 0; y < N; ++y) { | |
for (int x = 0; x < N; ++x) { | |
if (matrix[y * N + x]) { | |
valueToValues[y].emplace_back(x); | |
edges.emplace_back(x, y); | |
} | |
} | |
} | |
double score; | |
double bestScore = 1e9; | |
const int MultiStartNumber = (int)(25 * pow(40 / max(1.0, edges.size() / (double)N), 0.25)); | |
for (int _ = MultiStartNumber; _--; ) { | |
if (_) { | |
for (int i = 0; i < N; ++i) | |
indexToValue[i] = i; | |
random_shuffle(indexToValue, indexToValue + N, rando); | |
if (edges.empty()) | |
return { indexToValue, indexToValue + N }; | |
} else { | |
copy_n(bestIndexToValue, N, indexToValue); | |
} | |
init(); | |
score = eval(); | |
if (bestScore > score) { | |
bestScore = score; | |
copy_n(indexToValue, N, bestIndexToValue); | |
} | |
int ei = -1; | |
for (int iter = -1; ; ) { | |
if ((++iter & 0x1fff) == 0) { | |
double p = 1 - (getTime() - startTime - 8.85 / (MultiStartNumber - 1) * (MultiStartNumber - _ - 1)) / (_ ? 8.85 / (MultiStartNumber - 1) : 1); | |
if (p < 0) break; | |
const double InitialHeat = _ ? 0.4 : 0.1; | |
double heat = -p * InitialHeat; | |
for (int i = 0; i < 256; ++i) | |
transitionTh[i] = log((i + 1) / 257.0) * heat; | |
random_shuffle(transitionTh, transitionTh + 256, rando); | |
} | |
if (++ei == edges.size()) ei = 0; | |
int v1 = edges[ei].first; | |
int v2 = edges[ei].second; | |
int i1 = valueToIndex[v1]; | |
int i2 = valueToIndex[v2]; | |
int d = abs(i1 - i2); | |
d = min(d, N - d) - 1; | |
if (d == 0) continue; | |
if (++rangei[d] == d << 1) rangei[d] = 0; | |
i2 += ranget[d][rangei[d]]; | |
if (i2 < 0) { | |
i2 += N; | |
} else if (i2 >= N) { | |
i2 -= N; | |
} | |
v2 = indexToValue[i2]; | |
auto sin1 = sint - i1 + 200; | |
auto sin2 = sint - i2 + 200; | |
double d1, d2; | |
d1 = d2 = matrix[v1 * N + v2] ? sin1[i2] : 0; | |
for (unsigned char v : valueToValues[v1]) | |
d1 += sin2[valueToIndex[v]]; | |
for (unsigned char v : valueToValues[v2]) | |
d2 += sin1[valueToIndex[v]]; | |
double diff = d1 + d2 - valueToScore[v1] - valueToScore[v2]; | |
if (diff < transitionTh[iter & 255]) { | |
score += diff; | |
valueToIndex[v1] = i2; | |
valueToIndex[v2] = i1; | |
indexToValue[i1] = v2; | |
indexToValue[i2] = v1; | |
for (unsigned char v : valueToValues[v2]) | |
valueToScore[v] += sin1[valueToIndex[v]] - sin2[valueToIndex[v]]; | |
for (unsigned char v : valueToValues[v1]) | |
valueToScore[v] += sin2[valueToIndex[v]] - sin1[valueToIndex[v]]; | |
valueToScore[v1] = d1; | |
valueToScore[v2] = d2; | |
if (bestScore > score) { | |
bestScore = score; | |
copy_n(indexToValue, N, bestIndexToValue); | |
} | |
} | |
} | |
} | |
copy_n(bestIndexToValue, N, indexToValue); | |
for (int i = 0; i < N; ++i) | |
valueToIndex[indexToValue[i]] = i; | |
score = bestScore; | |
while (true) { | |
bool updated = false; | |
for (int i = 0; i < N; ++i) { | |
pair<double, int> best{ 0, i }; | |
double diff = 0; | |
for (int j = i + 1; j < N; ++j) { | |
for (unsigned char v : valueToValues[indexToValue[j - 1]]) { | |
if (valueToIndex[v] < j) { | |
diff += diffs[j - valueToIndex[v] - 1]; | |
} else { | |
diff -= diffs[valueToIndex[v] - j]; | |
} | |
} | |
for (unsigned char v : valueToValues[indexToValue[j]]) { | |
if (valueToIndex[v] > j - 1) { | |
diff += diffs[valueToIndex[v] - j]; | |
} else { | |
diff -= diffs[j - valueToIndex[v] - 1]; | |
} | |
} | |
best = min(best, { diff, j }); | |
++valueToIndex[indexToValue[j - 1]]; | |
--valueToIndex[indexToValue[j]]; | |
swap(indexToValue[j - 1], indexToValue[j]); | |
} | |
for (int j = N - 1; j > i; --j) { | |
++valueToIndex[indexToValue[j - 1]]; | |
--valueToIndex[indexToValue[j]]; | |
swap(indexToValue[j - 1], indexToValue[j]); | |
} | |
diff = 0; | |
for (int j = i; j; --j) { | |
for (unsigned char v : valueToValues[indexToValue[j - 1]]) { | |
if (valueToIndex[v] < j) { | |
diff += diffs[j - valueToIndex[v] - 1]; | |
} else { | |
diff -= diffs[valueToIndex[v] - j]; | |
} | |
} | |
for (unsigned char v : valueToValues[indexToValue[j]]) { | |
if (valueToIndex[v] > j - 1) { | |
diff += diffs[valueToIndex[v] - j]; | |
} else { | |
diff -= diffs[j - valueToIndex[v] - 1]; | |
} | |
} | |
best = min(best, { diff, j - 1 }); | |
++valueToIndex[indexToValue[j - 1]]; | |
--valueToIndex[indexToValue[j]]; | |
swap(indexToValue[j - 1], indexToValue[j]); | |
} | |
score += best.first; | |
for (int j = 1; j <= best.second; ++j) { | |
++valueToIndex[indexToValue[j - 1]]; | |
--valueToIndex[indexToValue[j]]; | |
swap(indexToValue[j - 1], indexToValue[j]); | |
} | |
updated |= best.first < -1e-9; | |
if (getTime() - startTime > 9.95) break; | |
} | |
constexpr int L = 6; | |
for (int beg = 0; beg <= N - L; ++beg) { | |
int end = beg + L; | |
double ps[L][L]{}; | |
for (int i = beg; i < end; ++i) { | |
for (int j = beg; j < end; ++j) { | |
for (unsigned char v : valueToValues[indexToValue[i]]) { | |
if (valueToIndex[v] < beg) { | |
ps[i - beg][j - beg] += sint[j - valueToIndex[v] + 200]; | |
} else if (valueToIndex[v] >= end) { | |
ps[i - beg][j - beg] += sint[valueToIndex[v] - j + 200]; | |
} | |
} | |
} | |
} | |
double best = 1e9; | |
int currs[L]; | |
int bests[L]; | |
static vector<int> ii(L); | |
for (int i = 0; i < L; ++i) | |
ii[i] = i; | |
int v2i[L]; | |
static vector<pair<int, int>> es; | |
es.clear(); | |
for (int i = 1; i < L; ++i) { | |
for (int j = 0; j < i; ++j) { | |
if (matrix[indexToValue[beg + i] * N + indexToValue[beg + j]]) | |
es.emplace_back(j, i); | |
} | |
} | |
function<void (int, double)> dfs = [&](int d, double s) { | |
if (d == L) { | |
for (auto& e : es) | |
s += sint[v2i[e.first] - v2i[e.second] + 200]; | |
if (best > s) { | |
best = s; | |
copy_n(currs, L, bests); | |
} | |
} else { | |
for (int i = 0; i < (int)ii.size(); ++i) { | |
int iii = ii[i]; | |
double ss = s + ps[iii][d]; | |
v2i[iii] = d; | |
currs[d] = indexToValue[beg + iii]; | |
ii[i] = ii.back(); | |
ii.pop_back(); | |
dfs(d + 1, ss); | |
ii.emplace_back(ii[i]); | |
ii[i] = iii; | |
} | |
} | |
}; | |
dfs(0, 0); | |
for (int i = 0; i < L; ++i) { | |
if (indexToValue[beg + i] != bests[i]) { | |
indexToValue[beg + i] = bests[i]; | |
updated = true; | |
} | |
} | |
for (int i = beg; i < end; ++i) | |
valueToIndex[indexToValue[i]] = i; | |
if (getTime() - startTime > 9.95) break; | |
} | |
for (int i = 2; i < N; ++i) { | |
for (int j = 0; j < i - 1; ++j) { | |
double diff = matrix[indexToValue[i] * N + indexToValue[j]] ? sint[i - j + 200] * 2 : 0; | |
for (unsigned char v : valueToValues[indexToValue[i]]) | |
diff += sint[valueToIndex[v] - j + 200] - sint[valueToIndex[v] - i + 200]; | |
for (unsigned char v : valueToValues[indexToValue[j]]) | |
diff += sint[valueToIndex[v] - i + 200] - sint[valueToIndex[v] - j + 200]; | |
if (diff < -1e-9) { | |
score += diff; | |
swap(valueToIndex[indexToValue[i]], valueToIndex[indexToValue[j]]); | |
swap(indexToValue[i], indexToValue[j]); | |
updated = true; | |
} | |
} | |
if (getTime() - startTime > 9.95) break; | |
} | |
if (!updated || getTime() - startTime > 9.95) break; | |
} | |
return { indexToValue, indexToValue + N }; | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment