Submission #810627
Source Code Expand
#ifndef LOCAL
#define NDEBUG
#endif
#include <algorithm>
#include <cassert>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <string>
#include <vector>
using namespace std;
#define U(v) \
cerr << #v << ": " << (v) << endl
class timer {
int n = 0;
map<string, timer> ts;
public:
long long limit = 9500;
long long t = 0;
bool elapses() const {
return time() - t > limit;
}
void measure() {
t = time() - t;
++n;
}
void measure(const string& id) { // twice call pair
ts[id].measure();
}
void print(const string& id = "TOTAL") {
if (n % 2 && id == "TOTAL")
measure();
assert(n % 2 == 0);
for (auto& p : ts)
p.second.print(p.first);
fprintf(stderr, "%9s: %4lld, %d\n", id.c_str(), t, n / 2);
fflush(stderr);
}
static long long time() {
return clock() * 1000ll / CLOCKS_PER_SEC;
}
} timer;
class rando {
unsigned y = 2463534242;
public:
unsigned next() {
return y ^= (y ^= (y ^= y << 13) >> 17) << 5;
}
int next(int b) {
assert(b > 0);
return next() % b;
}
int next(int a, int b) {
return next(b - a) + a;
}
double nextDouble(double b = 1) {
return b * next() / (1ll << 32);
}
double nextDouble(double a, double b) {
return nextDouble(b - a) + a;
}
int operator() (int b) { // for random_shuffle()
return next(b);
}
} rando;
template <typename Score>
class Annealing {
const long long START_TIME;
const double DIFF_COEF, FINAL_HEAT, INITIAL_HEAT, HEAT_COEF;
Score th;
double heat;
public:
Annealing(double initialHeat, double finalHeat, int timeLimit, double diffCoef) :
START_TIME(min(timer.time(), timer.t + timeLimit - 1)),
DIFF_COEF(diffCoef),
FINAL_HEAT(finalHeat),
INITIAL_HEAT(max(FINAL_HEAT + 1, initialHeat)),
HEAT_COEF(log(FINAL_HEAT / INITIAL_HEAT) / (timeLimit - START_TIME + timer.t)) {
}
bool cool() {
heat = INITIAL_HEAT * exp((timer.time() - START_TIME) * HEAT_COEF);
th = (Score)(heat * DIFF_COEF);
return heat > FINAL_HEAT;
}
inline bool shouldTransit(Score diff) const {
return diff < th && rando.nextDouble() < exp(-diff / heat); //
}
};
struct Node {
int x, y, height, forward = 0, reverse = 0;
Node* begin, * end, * prev = nullptr, * next = nullptr;
Node() {}
Node(int x, int y, int height) : x(x), y(y), height(height) {}
};
void print(vector<Node>& cells) {
int i = 1;
while (true) {
for (; i < cells.size() && cells[i - 1].height < cells[i].height; ++i);
int j = i - 1;
while (i == cells.size() ? cells[i - 1].height : cells[i - 1].height >= cells[i].height) {
for (; j - 1 >= 0 && cells[j - 1].height && cells[j].height - cells[j - 1].height == 1; --j);
for (; j < i && cells[j].height == 0; ++j);
for (int k = i - 1; k >= j; --k) {
--cells[k].height;
cout << cells[k].y + 1 << ' ' << cells[k].x + 1 << endl;
}
}
if (i == cells.size()) break;
}
}
int diff(Node* n1, Node* n2) {
return max(0, n1->height - n2->height + 1);
}
int evalf(Node* n) {
return n->end->forward + n->end->height;
}
int evalr(Node* n) {
return n->begin->reverse + n->begin->height;
}
int eval(Node* n) {
return min(evalf(n), evalr(n));
}
int eval(Node* n1, Node* n2) {
return (n1->next ? n1->reverse : n1->forward) +
diff(n1, n2) + (n2->next ? evalf(n2) : evalr(n2));
}
int evalf(Node* n1, Node* n2) {
return n2->forward - n1->forward + n2->height;
}
int evalr(Node* n1, Node* n2) {
return n2->reverse - n1->reverse + n2->height;
}
int evalff(Node* n1, Node* n2) {
return min(n1->forward + diff(n1, n2) + evalf(n2, n2->end),
n2->reverse + diff(n2, n1) + evalr(n1, n1->begin));
}
int evalfr(Node* n1, Node* n2) {
return min(n1->forward + diff(n1, n2) + evalr(n2, n2->begin),
n2->forward + diff(n2, n1) + evalr(n1, n1->begin));
}
int evalrf(Node* n1, Node* n2) {
return min(n1->reverse + diff(n1, n2) + evalf(n2, n2->end),
n2->reverse + diff(n2, n1) + evalf(n1, n1->end));
}
int eval1(Node* n1, Node* n2) {
return min(evalf(n1, n2), evalr(n2, n1));
}
int manhattan(Node* n1, Node* n2) {
return abs(n1->x - n2->x) + abs(n1->y - n2->y);
}
void update(Node* b, Node* e) {
b->prev = e->next = nullptr;
b->begin = b;
b->end = e;
b->forward = 0;
for (auto n = b->next; n; n = n->next) {
n->begin = b;
n->end = e;
n->forward = n->prev->forward + diff(n->prev, n);
}
e->reverse = 0;
for (auto n = e->prev; n; n = n->prev)
n->reverse = n->next->reverse + diff(n->next, n);
}
void updateff(Node* b1, Node* b2, Node* e1, Node* e2) {
b2->next = e1;
e1->prev = b2;
update(b1, e2);
}
void updatefr(Node* b1, Node* b2, Node* e1, Node* e2) {
e2->prev = nullptr;
for (auto n = e1; n; n = n->next)
swap(n->next, n->prev);
updateff(b1, b2, e1, e2);
}
void updaterf(Node* b1, Node* b2, Node* e1, Node* e2) {
b2->prev = nullptr;
for (auto n = b1; n; n = n->next)
swap(n->next, n->prev);
updateff(b1, b2, e1, e2);
}
bool tryTransit(Node* n1, Node* n2) {
if (n1->prev == n2 || n1->next == n2) {
if (n1->prev == n2)
swap(n1, n2);
int s1 = eval(n1);
int s2 = eval1(n1->begin, n1) + eval1(n2, n2->end);
if (s1 > s2) {
update(n1->begin, n1);
update(n2, n2->end);
return true;
}
} else if (n1->prev && n1->next && n2->prev && n2->next) {
if (n1->begin == n2->begin)
return false;
int s1 = eval(n1) + eval(n2);
if (manhattan(n1->prev, n2->prev) == 1) {
int s2 = evalfr(n1->prev, n2->prev) + evalrf(n1, n2);
if (s1 > s2) {
updatefr(n1->begin, n1->prev, n2->prev, n2->begin);
updaterf(n1->end, n1, n2, n2->end);
return true;
}
} else if (manhattan(n1->prev, n2->next) == 1) {
int s2 = evalff(n1->prev, n2->next) + evalff(n2, n1);
if (s1 > s2) {
updateff(n1->begin, n1->prev, n2->next, n2->end);
updateff(n2->begin, n2, n1, n1->end);
return true;
}
} else if (manhattan(n1->next, n2->prev) == 1) {
int s2 = evalff(n2->prev, n1->next) + evalff(n1, n2);
if (s1 > s2) {
updateff(n2->begin, n2->prev, n1->next, n1->end);
updateff(n1->begin, n1, n2, n2->end);
return true;
}
} else if (manhattan(n1->next, n2->next) == 1) {
int s2 = evalrf(n1->next, n2->next) + evalfr(n1, n2);
if (s1 > s2) {
updaterf(n1->end, n1->next, n2->next, n2->end);
updatefr(n1->begin, n1, n2, n2->begin);
return true;
}
}
} else if (n1->prev && n1->next || n2->prev && n2->next) {
if (n1->prev && n1->next)
swap(n1, n2);
if (n1->begin != n2->begin) {
int s1 = eval(n1) + eval(n2);
int s2 = (n1->next ? n1->reverse : n1->forward) + diff(n1, n2);
int s3 = diff(n2, n1) + (n1->next ? evalf(n1) : evalr(n1));
int s4 = min(s2 + evalr(n2, n2->begin), n2->forward + s3) + eval1(n2->next, n2->end);
int s5 = min(s2 + evalf(n2, n2->end), n2->reverse + s3) + eval1(n2->begin, n2->prev);
if (s1 > s4 && s5 > s4) {
update(n2->next, n2->end);
if (n1->next)
updateff(n2->begin, n2, n1, n1->end);
else
updatefr(n2->begin, n2, n1, n1->begin);
return true;
} else if (s1 > s5) {
update(n2->begin, n2->prev);
if (n1->next)
updaterf(n1->end, n1, n2, n2->end);
else
updateff(n1->begin, n1, n2, n2->end);
return true;
}
} else {
int s1 = eval(n1);
if (n1->next) {
int s2 = min(n2->reverse + diff(n2, n1) + evalf(n1, n2->prev),
n1->reverse - n2->prev->reverse + diff(n1, n2) + evalf(n2, n2->end));
if (s1 > s2) {
updaterf(n2->end, n2, n1, n2->prev);
return true;
}
} else {
int s2 = min(n2->forward + diff(n2, n1) + evalr(n1, n2->next),
n1->forward - n2->next->forward + diff(n1, n2) + evalr(n2, n2->begin));
if (s1 > s2) {
updatefr(n2->begin, n2, n1, n2->next);
return true;
}
}
}
} else {
if (n1->begin == n2->begin)
return false;
int s1 = eval(n1) + eval(n2);
int s2 = min(eval(n1, n2), eval(n2, n1));
if (s1 > s2) {
if (n1->next && n2->next) {
updaterf(n1->end, n1, n2, n2->end);
} else if (n1->next) {
updateff(n2->begin, n2, n1, n1->end);
} else if (n2->next) {
updateff(n1->begin, n1, n2, n2->end);
} else {
updatefr(n1->begin, n1, n2, n2->begin);
}
return true;
}
}
return false;
}
using Score = int;
const int N = 30;
Node sol[N][N], bestSol[N][N];
Score score, bestScore;
Score eval(Node sol[][N]) {
Score score = 0;
for (int y = 0; y < N; ++y) {
for (int x = 0; x < N; ++x) {
auto n = &sol[y][x];
if (n == n->begin)
score += eval(n);
}
}
return score;
}
void copy(Node from[][N], Node to[][N]) {
for (int y = 0; y < N; ++y) {
for (int x = 0; x < N; ++x) {
auto& f = from[y][x];
auto& t = to[y][x];
t.forward = f.forward;
t.reverse = f.reverse;
t.begin = &to[f.begin->y][f.begin->x];
t.end = &to[f.end->y][f.end->x];
t.prev = f.prev ? &to[f.prev->y][f.prev->x] : nullptr;
t.next = f.next ? &to[f.next->y][f.next->x] : nullptr;
}
}
}
void transit(Score diff) {
score += diff;
if (bestScore > score) {
bestScore = score;
copy(sol, bestSol);
}
}
int main() {
timer.measure();
for (int y = 0; y < N; ++y) {
for (int x = 0; x < N; ++x) {
int h;
cin >> h;
sol[y][x] = bestSol[y][x] = { x, y, h };
sol[y][x].begin = sol[y][x].end = &sol[y][x];
bestSol[y][x].begin = bestSol[y][x].end = &bestSol[y][x];
}
}
score = bestScore = eval(sol);
// annealing
Annealing<Score> sa(
45500,
0.7,
9400,
7
);
int ANNEAL = -1;
while (++ANNEAL & 0x7ffff || sa.cool()) {
// select randomly adjacent two cells
Node* n1, * n2;
unsigned r = rando.next();
if (r & 0x8000) {
int x = (r & 0x7fff) % (N - 1) + 1;
int y = (r >> 17) % N;
n1 = &sol[y][x - 1];
n2 = &sol[y][x];
} else {
int x = (r & 0x7fff) % N;
int y = (r >> 17) % (N - 1) + 1;
n1 = &sol[y - 1][x];
n2 = &sol[y][x];
}
// neighbor1 split one path to two paths
if (n1->prev == n2 || n1->next == n2) {
if (n1->prev == n2)
swap(n1, n2);
int s1 = eval(n1);
int s2 = eval1(n1->begin, n1) + eval1(n2, n2->end);
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
update(n1->begin, n1);
update(n2, n2->end);
transit(diff);
}
// neighbor2 split and combine two paths
} else if (n1->prev && n1->next && n2->prev && n2->next) {
if (n1->begin == n2->begin) continue;
int s1 = eval(n1) + eval(n2);
if (manhattan(n1->prev, n2->prev) == 1) {
int s2 = evalfr(n1->prev, n2->prev) + evalrf(n1, n2);
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
updatefr(n1->begin, n1->prev, n2->prev, n2->begin);
updaterf(n1->end, n1, n2, n2->end);
transit(diff);
}
} else if (manhattan(n1->prev, n2->next) == 1) {
int s2 = evalff(n1->prev, n2->next) + evalff(n2, n1);
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
updateff(n1->begin, n1->prev, n2->next, n2->end);
updateff(n2->begin, n2, n1, n1->end);
transit(diff);
}
} else if (manhattan(n1->next, n2->prev) == 1) {
int s2 = evalff(n2->prev, n1->next) + evalff(n1, n2);
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
updateff(n2->begin, n2->prev, n1->next, n1->end);
updateff(n1->begin, n1, n2, n2->end);
transit(diff);
}
} else if (manhattan(n1->next, n2->next) == 1) {
int s2 = evalrf(n1->next, n2->next) + evalfr(n1, n2);
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
updaterf(n1->end, n1->next, n2->next, n2->end);
updatefr(n1->begin, n1, n2, n2->begin);
transit(diff);
}
}
} else if (n1->prev && n1->next || n2->prev && n2->next) {
if (n1->prev && n1->next)
swap(n1, n2);
// neighbor3 split one path includes n2 to two paths. combine splitted one path and one path includes n1
if (n1->begin != n2->begin) {
int s1 = eval(n1) + eval(n2);
int s2 = (n1->next ? n1->reverse : n1->forward) + diff(n1, n2);
int s3 = diff(n2, n1) + (n1->next ? evalf(n1) : evalr(n1));
if (r & 0x10000) {
int s4 = min(s2 + evalr(n2, n2->begin), n2->forward + s3) + eval1(n2->next, n2->end);
Score diff = s4 - s1;
if (sa.shouldTransit(diff)) {
update(n2->next, n2->end);
if (n1->next)
updateff(n2->begin, n2, n1, n1->end);
else
updatefr(n2->begin, n2, n1, n1->begin);
transit(diff);
}
} else {
int s5 = min(s2 + evalf(n2, n2->end), n2->reverse + s3) + eval1(n2->begin, n2->prev);
Score diff = s5 - s1;
if (sa.shouldTransit(diff)) {
update(n2->begin, n2->prev);
if (n1->next)
updaterf(n1->end, n1, n2, n2->end);
else
updateff(n1->begin, n1, n2, n2->end);
transit(diff);
}
}
// neighbor4 split and combine one path
} else {
int s1 = eval(n1);
if (n1->next) {
int s2 = min(n2->reverse + diff(n2, n1) + evalf(n1, n2->prev),
n1->reverse - n2->prev->reverse + diff(n1, n2) + evalf(n2, n2->end));
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
updaterf(n2->end, n2, n1, n2->prev);
transit(diff);
}
} else {
int s2 = min(n2->forward + diff(n2, n1) + evalr(n1, n2->next),
n1->forward - n2->next->forward + diff(n1, n2) + evalr(n2, n2->begin));
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
updatefr(n2->begin, n2, n1, n2->next);
transit(diff);
}
}
}
// neighbor5 combine two paths to one path
} else {
if (n1->begin == n2->begin) continue;
int s1 = eval(n1) + eval(n2);
int s2 = min(eval(n1, n2), eval(n2, n1));
Score diff = s2 - s1;
if (sa.shouldTransit(diff)) {
if (n1->next && n2->next) {
updaterf(n1->end, n1, n2, n2->end);
} else if (n1->next) {
updateff(n2->begin, n2, n1, n1->end);
} else if (n2->next) {
updateff(n1->begin, n1, n2, n2->end);
} else {
updatefr(n1->begin, n1, n2, n2->begin);
}
transit(diff);
}
}
}
copy(bestSol, sol);
// hill climbing
while (true) {
bool any = false;
for (int y = 0; y < N; ++y)
for (int x = 1; x < N; ++x)
any |= tryTransit(&sol[y][x - 1], &sol[y][x]);
for (int y = 1; y < N; ++y)
for (int x = 0; x < N; ++x)
any |= tryTransit(&sol[y - 1][x], &sol[y][x]);
if (!any) break;
}
for (int y = 0; y < N; ++y) {
for (int x = 0; x < N; ++x) {
auto n = &sol[y][x];
if (n != n->begin) continue;
vector<Node> cells;
if (evalf(n) < evalr(n)) {
for (; n; n = n->next)
cells.emplace_back(*n);
} else {
for (n = n->end; n; n = n->prev)
cells.emplace_back(*n);
}
print(cells);
}
}
return 0;
}
Submission Info
Submission Time |
|
Task |
A - 高橋君の山崩しゲーム |
User |
hakomo |
Language |
C++14 (GCC 5.4.1) |
Score |
897918 |
Code Size |
18588 Byte |
Status |
AC |
Exec Time |
9771 ms |
Memory |
768 KB |
Judge Result
Set Name |
test_01 |
test_02 |
test_03 |
test_04 |
test_05 |
test_06 |
test_07 |
test_08 |
test_09 |
test_10 |
Score / Max Score |
89977 / 100000 |
89676 / 100000 |
89787 / 100000 |
89565 / 100000 |
89664 / 100000 |
89733 / 100000 |
90194 / 100000 |
89621 / 100000 |
89748 / 100000 |
89953 / 100000 |
Status |
|
|
|
|
|
|
|
|
|
|
Set Name |
Test Cases |
test_01 |
subtask_01_01.txt |
test_02 |
subtask_01_02.txt |
test_03 |
subtask_01_03.txt |
test_04 |
subtask_01_04.txt |
test_05 |
subtask_01_05.txt |
test_06 |
subtask_01_06.txt |
test_07 |
subtask_01_07.txt |
test_08 |
subtask_01_08.txt |
test_09 |
subtask_01_09.txt |
test_10 |
subtask_01_10.txt |
Case Name |
Status |
Exec Time |
Memory |
subtask_01_01.txt |
AC |
9740 ms |
640 KB |
subtask_01_02.txt |
AC |
9766 ms |
640 KB |
subtask_01_03.txt |
AC |
9762 ms |
640 KB |
subtask_01_04.txt |
AC |
9760 ms |
768 KB |
subtask_01_05.txt |
AC |
9748 ms |
640 KB |
subtask_01_06.txt |
AC |
9771 ms |
640 KB |
subtask_01_07.txt |
AC |
9755 ms |
640 KB |
subtask_01_08.txt |
AC |
9732 ms |
640 KB |
subtask_01_09.txt |
AC |
9754 ms |
640 KB |
subtask_01_10.txt |
AC |
9767 ms |
640 KB |