Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Author: Psyho
- // Blog: http://psyho.gg/
- // Twitter: https://twitter.com/fakepsyho
- const double TIME_MULT = 1.0;
- const bool FULL_EVALUATE = false;
- #include <bits/stdc++.h>
- // #include <time.h>
- using namespace std;
- #undef assert
- #define assert(x) ;
- #define INLINE inline __attribute__ ((always_inline))
- #define NOINLINE __attribute__ ((noinline))
- #define ALIGNED __attribute__ ((aligned(16)))
- #define likely(x) __builtin_expect(!!(x),1)
- #define unlikely(x) __builtin_expect(!!(x),0)
- #define SSELOAD(a) _mm_load_si128((__m128i*)&a)
- #define SSESTORE(a, b) _mm_store_si128((__m128i*)&a, b)
- #define FOR(i,a,b) for(int i=(a);i<(b);++i)
- #define REP(i,a) FOR(i,0,a)
- #define ZERO(m) memset(m,0,sizeof(m))
- #define ALL(x) x.begin(),x.end()
- #define PB push_back
- #define S size()
- #define byte unsigned char
- #define LL long long
- #define ULL unsigned long long
- #define LD long double
- #define MP make_pair
- #define X first
- #define Y second
- #define VC vector
- #define PII pair<int, int>
- #define PDD pair<double, double>
- #define VI VC<int>
- #define VVI VC<VI>
- #define VVVI VC<VVI>
- #define VPII VC<PII>
- #define VVPII VC<VPII>
- #define VVVPII VC<VVPII>
- #define VD VC<double>
- #define VVD VC<VD>
- #define VVVD VC<VVD>
- #define VPDD VC<PDD>
- #define VVPDD VC<VPDD>
- #define VVVPDD VC<VVPDD>
- #define VS VC<string>
- #define VVS VC<VS>
- #define VVVS VC<VVS>
- #define DB(a) cerr << #a << ": " << (a) << endl;
- template<class A, class B> ostream& operator<<(ostream &os, pair<A,B> p) {os << "(" << p.X << "," << p.Y << ")"; return os;}
- template<class A, class B, class C> ostream& operator<<(ostream &os, tuple<A,B,C> p) {os << "(" << get<0>(p) << "," << get<1>(p) << "," << get<2>(p) << ")"; return os;}
- template<class T> ostream& operator<<(ostream &os, VC<T> v) {os << "{"; REP(i, v.S) {if (i) os << ", "; os << v[i];} os << "}"; return os;}
- template<class T> ostream& operator<<(ostream &os, set<T> s) {VS vs(ALL(s)); return os << vs;}
- template<class T> string i2s(T x) {ostringstream o; o << x; return o.str();}
- VS splt(string s, char c = ' ') {VS all; int p = 0, np; while (np = s.find(c, p), np >= 0) {all.PB(s.substr(p, np - p)); p = np + 1;} all.PB(s.substr(p)); return all;}
- double getTime() {
- ULL timelo, timehi;
- __asm__ volatile ("rdtsc" : "=a" (timelo), "=d" (timehi));
- return ((timehi << 32) + timelo) / 2.5e9;
- // timespec tv;
- // clock_gettime(CLOCK_MONOTONIC, &tv);
- // return tv.tv_sec + 1e-9 * tv.tv_nsec;
- }
- struct RNG {
- unsigned int x = 123456789;
- unsigned int y = 362436069;
- unsigned int z = 521288629;
- unsigned int rand() {
- x ^= x << 16;
- x ^= x >> 5;
- x ^= x << 1;
- unsigned int t = x;
- x = y;
- y = z;
- z = t ^ x ^ y;
- return z;
- }
- INLINE int next(int x) {
- return rand() % x;
- }
- INLINE int nextAnd(int x) {
- return rand() & x;
- }
- INLINE int next(int a, int b) {
- return a + (rand() % (b - a));
- }
- INLINE double nextDouble() {
- return (rand() + 0.5) * (1.0 / 4294967296.0);
- }
- template<class T>
- INLINE void shuffle(VC<T> &v, int end = -1) {
- if (end == -1) end = v.S;
- REP(i, end) swap(v[i], v[next(i, v.S)]);
- }
- };
- RNG rng;
- template <int MAXV>
- class MCMF {
- struct Edge {
- int target;
- int flow;
- int cost;
- int reverse;
- Edge(int target, int flow, int cost, int reverse) {
- this->target = target;
- this->flow = flow;
- this->cost = cost;
- this->reverse = reverse;
- }
- };
- VC<Edge> edges[MAXV];
- int prev[MAXV];
- int dist[MAXV];
- int queueExist[MAXV];
- int queueData[MAXV + 1];
- int queueStart;
- int queueEnd;
- int source;
- int sink;
- public:
- MCMF(int source, int sink) {
- this->source = source;
- this->sink = sink;
- }
- void addEdge(int a, int b, int flow, int cost = 0) {
- int sa = edges[a].S;
- int sb = edges[b].S;
- edges[a].PB(Edge(b, flow, cost, sb));
- edges[b].PB(Edge(a, 0, -cost, sa));
- }
- int checkFlow(int a, int b) {
- for (Edge &edge : edges[b]) if (edge.target == a) return edge.flow;
- return 0;
- }
- private:
- bool queueDone() {
- return queueStart == queueEnd;
- }
- void queueClear() {
- ZERO(queueExist);
- queueStart = 0;
- queueEnd = 0;
- }
- int queuePop() {
- int rv = queueData[queueStart];
- queueExist[rv] = false;
- queueStart = (queueStart + 1) % (MAXV + 1);
- return rv;
- }
- void queueAdd(int v) {
- if (queueExist[v]) return;
- queueExist[v] = true;
- queueData[queueEnd] = v;
- queueEnd = (queueEnd + 1) % (MAXV + 1);
- }
- public:
- LL run() {
- LL totalCost = 0;
- int totalFlow = 0;
- while (true) {
- memset(dist, 0x3F, sizeof(dist));
- dist[source] = 0;
- prev[sink] = -1;
- prev[source] = -1;
- queueClear();
- queueAdd(source);
- while (!queueDone()) {
- int v = queuePop();
- REP(i, edges[v].S) if (edges[v][i].flow > 0 && dist[edges[v][i].target] > dist[v] + edges[v][i].cost) {
- dist[edges[v][i].target] = dist[v] + edges[v][i].cost;
- prev[edges[v][i].target] = edges[v][i].reverse;
- queueAdd(edges[v][i].target);
- }
- }
- if (prev[sink] == -1 || dist[sink] > (1 << 20)) break;
- int maxFlow = 1 << 30;
- int v = sink;
- while (v != source) {
- int pv = edges[v][prev[v]].target;
- maxFlow = min(maxFlow, edges[pv][edges[v][prev[v]].reverse].flow);
- v = pv;
- }
- assert(maxFlow > 0);
- totalFlow += maxFlow;
- v = sink;
- while (v != source) {
- int pv = edges[v][prev[v]].target;
- edges[pv][edges[v][prev[v]].reverse].flow -= maxFlow;
- edges[v][prev[v]].flow += maxFlow;
- totalCost += edges[pv][edges[v][prev[v]].reverse].cost * maxFlow;
- v = pv;
- }
- }
- return totalCost;
- }
- };
- const int MAX_STARS = 2000;
- const int MAX_UFOS = 20;
- const int MAX_SHIPS = 10;
- const int MAX_NEIGHBOURS = 30;
- const double UFO_MULT = 0.001;
- PII PP[MAX_STARS];
- double OPD[MAX_STARS][MAX_STARS+4];
- double PD[MAX_STARS][MAX_STARS+4];
- int PN[MAX_STARS][MAX_STARS];
- int PO[MAX_STARS][MAX_STARS];
- int PC[MAX_STARS][MAX_NEIGHBOURS];
- PII PPOS[MAX_STARS];
- int PNO;
- int SP[MAX_SHIPS];
- int SNO;
- VI UFOS[MAX_UFOS];
- int UNO;
- int UPROBTURN = -1000;
- VI UPROB[MAX_UFOS];
- int UFOUSED[MAX_UFOS];
- double UFODIST[MAX_UFOS];
- bool USEREALUFOW = false;
- int REALUFOW[MAX_UFOS];
- double PEXPCOST;
- int XVSNO = 1;
- int XVS[MAX_STARS];
- int vs[MAX_STARS];
- int vscopy[MAX_STARS];
- int totvs = 0;
- int turn = -1;
- const int MCMST_SIMS = 25;
- const int UFO_DIST_SIZE = 32768;
- // const double TOLERANCE = 100;
- const double TIME_LIMIT = 19.5 * TIME_MULT;
- const double MAX_MC_TIME = 10.0 * TIME_MULT;
- const double MAX_MCMST_TIME = 15.0 * TIME_MULT;
- int NEXTMOVE[MAX_SHIPS];
- double totalTime = 0;
- int TPATH[MAX_STARS+10];
- int PATH[MAX_SHIPS][MAX_STARS+10];
- int PATHLEN[MAX_SHIPS];
- int PATHTURN[MAX_SHIPS];
- int BPATH[MAX_SHIPS][MAX_STARS+10];
- int BPATHLEN[MAX_SHIPS];
- double BPATHSUM[MAX_SHIPS][MAX_STARS+10];
- bool FINAL_PATH = false;
- int hops = 0;
- int detours = 0;
- int hopped[MAX_SHIPS];
- VI bestMatching(VVI &w) {
- assert(w.S == SNO);
- REP(i, SNO) assert(w[i].S == UNO);
- MCMF<42> mcmf(40, 41);
- REP(i, SNO) REP(j, UNO) if (w[i][j] >= 0) mcmf.addEdge(i, 20 + j, 1, w[i][j]);
- REP(i, SNO) mcmf.addEdge(40, i, 1, 0);
- REP(i, UNO) mcmf.addEdge(20 + i, 41, 1, 0);
- mcmf.run();
- VI rv(SNO, -1);
- REP(i, SNO) REP(j, UNO) if (mcmf.checkFlow(i, 20 + j)) rv[i] = j;
- return rv;
- }
- struct Strategy {
- int hopSize;
- bool transport;
- VI forceUfo;
- Strategy() {
- hopSize = 0;
- transport = false;
- }
- };
- Strategy str;
- double calcSolution(int s) {
- double rv = 0;
- REP(i, PATHLEN[s]-1) rv += PD[PATH[s][i]][PATH[s][i+1]];
- return rv;
- }
- double calcSolution() {
- double rv = 0;
- REP(s, SNO) REP(i, PATHLEN[s]-1) rv += PD[PATH[s][i]][PATH[s][i+1]];
- return rv;
- }
- INLINE double pathDist(int s, int pos, int p) {
- return PD[PATH[s][pos]][p];
- }
- double greedy(VI pos, VI planets) {
- double rv = 0;
- REP(s, SNO) {
- PATHLEN[s] = 1;
- PATH[s][0] = pos[0];
- }
- while (planets.S) {
- double bv = 1e30;
- int bs = -1;
- int bp = -1;
- int bi = -1;
- REP(s, SNO) FOR(p, 1, PATHLEN[s]+1) REP(i, planets.S) {
- double av = 0;
- av += PD[PATH[s][p-1]][planets[i]];
- if (p < PATHLEN[s]) av += PD[PATH[s][p]][planets[i]];
- if (av < bv) {
- bv = av;
- bs = s;
- bp = p;
- bi = i;
- }
- }
- PATHLEN[bs]++;
- for (int i = PATHLEN[bs]; i > bp; i--) PATH[bs][i] = PATH[bs][i-1];
- PATH[bs][bp] = planets[bi];
- rv += bv;
- planets[bi] = planets.back();
- planets.pop_back();
- }
- return rv;
- }
- double quickLB(VI &vs, VI &ships) {
- double rv = 0;
- double nearShip = 1e30;
- REP(i, PNO) if (!vs[i]) {
- int found = 0;
- double d1 = 0;
- double d2 = 0;
- FOR(j, 1, PNO) {
- int p = PN[i][j];
- if (!vs[p]) {
- rv += PD[i][p];
- if (++found >= 2) break;
- }
- }
- REP(j, ships.S) nearShip = min(nearShip, PD[i][ships[j]]);
- }
- rv /= 2;
- return rv + (nearShip > 1e10 ? 0 : nearShip);
- }
- VI genDistribution(int no, int x, int size) {
- VI rv(size);
- REP(i, size) {
- rv[i] = no;
- REP(j, x) rv[i] = min(rv[i], rng.next(1, no));
- }
- return rv;
- }
- struct State {
- VI vs;
- VI ships;
- VI hopped;
- VVI ufo;
- VI ufow;
- VVI ufoprob;
- int offset;
- int turnsLeft;
- };
- int FUP[MAX_STARS];
- int FUR[MAX_STARS];
- void FUinit(int n) {
- REP(i, n) FUP[i] = i;
- REP(i, n) FUR[i] = 0;
- }
- void FUunion(int x, int y) {
- int xr = FUP[x];
- int yr = FUP[y];
- if (xr == yr) return;
- if (FUR[xr] < FUR[yr]) {
- FUP[xr] = yr;
- } else if (FUR[xr] > FUR[yr]) {
- FUP[yr] = xr;
- } else {
- FUP[yr] = xr;
- FUR[xr]++;
- }
- }
- int FUfind(int x) {
- return FUP[x] == x ? x : FUP[x] = FUfind(FUP[x]);
- }
- double calcMST() {
- VI v;
- REP(i, PNO) if (!vs[i]) v.PB(i);
- if (v.S <= 1) return 0;
- FUinit(v.S);
- priority_queue<pair<double,PII>> pq;
- REP(i, v.S) REP(j, i) pq.push(MP(-PD[v[i]][v[j]], MP(i, j)));
- double rv = 0;
- int edgesAdded = 1;
- while (edgesAdded < v.S) {
- auto p = pq.top(); pq.pop();
- if (FUfind(p.Y.X) == FUfind(p.Y.Y)) continue;
- rv += -p.X;
- edgesAdded++;
- FUunion(p.Y.X, p.Y.Y);
- }
- return rv;
- }
- double calcMST(VI &ships) {
- VI v;
- REP(i, PNO) if (!vs[i]) v.PB(i);
- if (v.S == 0) return 0;
- FUinit(v.S+1);
- priority_queue<pair<double,PII>> pq;
- REP(i, v.S) REP(j, i) pq.push(MP(-PD[v[i]][v[j]], MP(i, j)));
- REP(i, v.S) {
- double minDist = 1e30;
- REP(j, ships.S) minDist = min(minDist, PD[v[i]][ships[j]]);
- pq.push(MP(-minDist, MP(i, v.S)));
- }
- double rv = 0;
- int edgesAdded = 0;
- while (edgesAdded < v.S) {
- auto p = pq.top(); pq.pop();
- if (FUfind(p.Y.X) == FUfind(p.Y.Y)) continue;
- rv += -p.X;
- edgesAdded++;
- FUunion(p.Y.X, p.Y.Y);
- }
- return rv;
- }
- double calcMST(VI &vs, VI &ships) {
- VI v;
- REP(i, PNO) if (!vs[i]) v.PB(i);
- if (v.S == 0) return 0;
- FUinit(v.S+1);
- priority_queue<pair<double,PII>> pq;
- REP(i, v.S) REP(j, i) pq.push(MP(-PD[v[i]][v[j]], MP(i, j)));
- REP(i, v.S) {
- double minDist = 1e30;
- REP(j, ships.S) minDist = min(minDist, PD[v[i]][ships[j]]);
- pq.push(MP(-minDist, MP(i, v.S)));
- }
- double rv = 0;
- int edgesAdded = 0;
- while (edgesAdded < v.S) {
- auto p = pq.top(); pq.pop();
- if (FUfind(p.Y.X) == FUfind(p.Y.Y)) continue;
- rv += -p.X;
- edgesAdded++;
- FUunion(p.Y.X, p.Y.Y);
- }
- return rv;
- }
- const int MCMST_MAX_TURNS = 300;
- const int MCMST_MAX_PLANETS = 300;
- #define PDII pair<double, PII>
- int MCMSTEDGESNO = 0;
- int MCMSTXEDGESNO = 0;
- PDII MCMSTEDGES[MCMST_MAX_PLANETS * MCMST_MAX_PLANETS + 4];
- PDII MCMSTXEDGES[MCMST_MAX_PLANETS];
- double calcMCMST(VI final, VI ufo, VI ufoused, int turns, int sims) {
- VC<RNG> r(UNO); REP(u, ufo.S) REP(i, turns) r[u].rand();
- double rv = 0;
- double ud = 0;
- REP(i, PNO) vscopy[i] = vs[i];
- VI ov;
- REP(i, PNO) if (!vs[i]) ov.PB(i);
- MCMSTEDGESNO = 0;
- REP(i, ov.S) REP(j, i) MCMSTEDGES[MCMSTEDGESNO++] = MP(PD[ov[i]][ov[j]], MP(i, j));
- sort(MCMSTEDGES, MCMSTEDGES + MCMSTEDGESNO);
- MCMSTEDGES[MCMSTEDGESNO].X = 1e30;
- REP(sim, sims) {
- REP(i, PNO) vs[i] = vscopy[i];
- VI pos = final;
- REP(i, UNO) if (ufoused[i]) {
- int x = ufo[i];
- REP(t, turns) {
- int y = PN[x][UPROB[i][r[i].nextAnd(UFO_DIST_SIZE-1)]];
- // ud += PD[x][y];
- x = y;
- vs[x] = 1;
- }
- pos.PB(x);
- }
- assert(pos.S == SNO);
- FUinit(ov.S+1);
- MCMSTXEDGESNO = 0;
- REP(i, ov.S) if (!vs[ov[i]]) {
- double minDist = 1e30;
- REP(j, pos.S) minDist = min(minDist, PD[ov[i]][pos[j]]);
- MCMSTXEDGES[MCMSTXEDGESNO++] = MP(minDist, MP(i, ov.S));
- }
- sort(MCMSTXEDGES, MCMSTXEDGES + MCMSTXEDGESNO);
- MCMSTXEDGES[MCMSTXEDGESNO].X = 1e30;
- int EPOS = 0;
- int XEPOS = 0;
- int edgesAdded = 0;
- while (edgesAdded < MCMSTXEDGESNO) {
- if (MCMSTEDGES[EPOS].X < MCMSTXEDGES[XEPOS].X) {
- auto &p = MCMSTEDGES[EPOS++];
- if (vs[ov[p.Y.X]] || vs[ov[p.Y.Y]]) continue;
- if (FUfind(p.Y.X) == FUfind(p.Y.Y)) continue;
- rv += p.X;
- edgesAdded++;
- FUunion(p.Y.X, p.Y.Y);
- } else {
- auto &p = MCMSTXEDGES[XEPOS++];
- if (vs[ov[p.Y.X]]) continue;
- if (FUfind(p.Y.X) == FUfind(p.Y.Y)) continue;
- rv += p.X;
- edgesAdded++;
- FUunion(p.Y.X, p.Y.Y);
- }
- }
- }
- REP(i, PNO) vs[i] = vscopy[i];
- // rv += ud * UFO_MULT;
- rv /= sims;
- return rv;
- }
- double monteCarlo(State &state, Strategy &str) {
- VI vs = state.vs;
- int planetsLeft = 0;
- REP(i, PNO) if (!vs[i]) planetsLeft++;
- if (planetsLeft == 0) return 0;
- int opl = planetsLeft;
- int hopSize = str.hopSize;
- double rv = 0;
- VI ufos = state.ufo[0];
- VI next = state.ufo[0];
- VI ships = state.ships;
- VI usedUfo(UNO, -1);
- VI hopped = state.hopped;
- int turn = 0;
- // First Turn
- VVI w(SNO, VI(UNO, -1));
- REP(s, SNO) REP(u, UNO) {
- double minDist = 1e30;
- if (ships[s] == state.ufo[0][u]) minDist = 0;
- minDist = min(minDist, PD[ships[s]][state.ufo[1][u]]);
- minDist = min(minDist, PD[ships[s]][state.ufo[2][u]]);
- if (minDist > hopSize && !str.forceUfo[u]) continue;
- if (hopped[s] && !str.forceUfo[u] && minDist > 0) continue;
- w[s][u] = (int)round(minDist) + (str.forceUfo[u] ? 0 : 2000);
- }
- VI matching = bestMatching(w);
- REP(s, SNO) if (matching[s] != -1) {
- int u = matching[s];
- int p = ships[s] == state.ufo[0][u] || PD[ships[s]][state.ufo[1][u]] < PD[ships[s]][state.ufo[2][u]] ? state.ufo[1][u] : state.ufo[2][u];
- rv += PD[ships[s]][p] * (ships[s] == state.ufo[0][u] ? UFO_MULT : 1.0);
- hopped[s] = 1;
- ships[s] = p;
- planetsLeft -= vs[p] == 0;
- vs[p] = 1;
- }
- ufos = state.ufo[1];
- turn++;
- //Rest
- while (state.turnsLeft - turn > planetsLeft && planetsLeft) {
- if (turn >= 2) {
- REP(i, UNO) next[i] = PN[ufos[i]][state.ufoprob[i][turn]];
- } else if (turn == 1) {
- next = state.ufo[2];
- }
- int firstShip = 0;
- REP(u, UNO) {
- double bv = 1e30;
- int bs = -1;
- FOR(s, firstShip, SNO) {
- if (ships[s] != ufos[u]) {
- if (hopped[s] || PD[ships[s]][next[u]] > hopSize) continue;
- if (PD[ships[s]][next[u]] < bv) {
- bv = PD[ships[s]][next[u]];
- bs = s;
- }
- } else {
- bs = s;
- break;
- }
- }
- if (bs == -1) continue;
- hopped[bs] = 1;
- rv += PD[ships[bs]][next[u]] * (ships[bs] == ufos[u] ? UFO_MULT : 1.0);
- planetsLeft -= vs[next[u]] == 0;
- vs[next[u]] = 1;
- ships[bs] = next[u];
- swap(ships[firstShip], ships[bs]);
- swap(hopped[firstShip], hopped[bs]);
- firstShip++;
- }
- REP(i, UNO) ufos[i] = next[i];
- turn++;
- }
- return rv + quickLB(vs, ships);
- }
- VD monteCarlo(State &state, VC<Strategy> &str, VVI beam) {
- VD rv(str.S);
- VI left; REP(i, str.S) left.PB(i);
- int totalSims = 0;
- for (VI &beamLevel : beam) {
- REP (i, beamLevel[0]) {
- REP(u, UNO) rng.shuffle(state.ufoprob[u], state.turnsLeft + 5);
- for (int j : left) rv[j] += monteCarlo(state, str[j]);
- }
- totalSims += beamLevel[0];
- VC<pair<double, int>> vp;
- for (int j : left) vp.PB(MP(rv[j], j));
- sort(ALL(vp));
- left.clear();
- REP(i, beamLevel[1]) left.PB(vp[i].Y);
- FOR(i, beamLevel[1], vp.S) rv[vp[i].Y] /= totalSims;
- REP(i, rv.S) rv[i] += 10000;
- }
- return rv;
- }
- double monteCarlo(State &state, Strategy &str, VVVI &prob, int from = -1, int to = -1) {
- if (to == -1) from = 0, to = prob.S;
- double rv = 0;
- FOR(i, from, to) {
- REP(u, UNO) state.ufoprob[u] = prob[i][u];
- rv += monteCarlo(state, str);
- }
- return rv / (to - from);
- }
- INLINE void updatePPOS(int s, int a, int b) {
- FOR(i, a, b+1) PPOS[PATH[s][i]] = MP(s, i);
- }
- bool performDetourStarted = false;
- double finalPathGain = 0;
- void showFinalStats() {
- cerr << "[Final Stats]" << endl;
- cerr << "TestTime = " << totalTime << endl;
- if (abs(finalPathGain) <= 1e-6) finalPathGain = 0;
- DB(finalPathGain);
- }
- class StarTraveller {public:
- void passUfoW(VI &ufow) {
- USEREALUFOW = true;
- REP(i, ufow.S) REALUFOW[i] = ufow[i];
- }
- int init(VI &stars) {
- // REP(i, 123456) rng.rand();
- auto startTime = getTime();
- PNO = stars.S / 2;
- REP(i, PNO) PP[i] = MP(stars[i*2], stars[i*2+1]);
- REP(i, PNO) REP(j, PNO) PD[i][j] = sqrt((PP[i].X-PP[j].X)*(PP[i].X-PP[j].X) + (PP[i].Y-PP[j].Y)*(PP[i].Y-PP[j].Y));
- pair<double, int> vp[MAX_STARS];
- REP(i, PNO) {
- REP(j, PNO) vp[j] = MP(PD[i][j], j);
- sort(vp, vp + PNO);
- REP(j, PNO) PO[i][vp[j].Y] = j;
- REP(j, PNO) PN[i][j] = vp[j].Y;
- }
- memset(PATH, -1, sizeof(PATH));
- memset(NEXTMOVE, -1, sizeof(NEXTMOVE));
- totalTime += getTime() - startTime;
- DB(totalTime);
- return 0;
- }
- VI makeMoves(VI ufos, VI ships) {
- auto startTime = getTime();
- turn++;
- int turnsLeft = 4 * PNO - turn;
- if (FINAL_PATH) {
- bool done = true;
- REP(s, SNO) {
- int bp = PATHTURN[s]+1<BPATHLEN[s] ? BPATH[s][PATHTURN[s]+1] : ships[s];
- bool useufo = false;
- bool shortcut = false;
- double bv = PD[ships[s]][bp];
- REP(u, UNO) {
- if (ufos[u*3] == ships[s]) {
- double av1 = BPATHLEN[s]-PATHTURN[s]-1<=turnsLeft ? UFO_MULT * PD[ships[s]][ufos[u*3+1]] + PD[ufos[u*3+1]][BPATH[s][PATHTURN[s]+1]] : 1e30;
- double av2 = BPATHLEN[s]-PATHTURN[s]+0<=turnsLeft ? UFO_MULT * (PD[ships[s]][ufos[u*3+1]] + PD[ufos[u*3+1]][ufos[u*3+2]]) + PD[ufos[u*3+2]][BPATH[s][PATHTURN[s]+1]] : 1e30;
- double av = min(av1, av2);
- if (av < bv) {
- if (av1 < av2) finalPathGain += bv - av;
- bv = av;
- shortcut = true;
- useufo = true;
- bp = ufos[u*3+1];
- }
- } else {
- double av = BPATHLEN[s]-PATHTURN[s]+0<=turnsLeft ? UFO_MULT * PD[ufos[u*3+1]][ufos[u*3+2]] + PD[ships[s]][ufos[u*3+1]] + PD[ufos[u*3+2]][BPATH[s][PATHTURN[s]+1]] : 1e30;
- if (av < bv) {
- bv = av;
- shortcut = true;
- useufo = false;
- bp = ufos[u*3+1];
- }
- }
- }
- if (!shortcut && ufos.S && BPATHLEN[s]-PATHTURN[s]+1<=turnsLeft && PATHTURN[s]+1<BPATHLEN[s]) {
- if (rng.nextDouble() < PD[ships[s]][bp] * (turnsLeft-(BPATHLEN[s]-PATHTURN[s])) / (BPATHSUM[s][BPATHLEN[s]]-BPATHSUM[s][PATHTURN[s]]+1e-3)) {
- done = false;
- continue;
- }
- }
- PATHTURN[s] += bp == BPATH[s][PATHTURN[s]+1];
- done &= PATHTURN[s] >= BPATHLEN[s]-1;
- finalPathGain -= PD[ships[s]][bp] * (useufo ? UFO_MULT : 1.0);
- ships[s] = bp;
- }
- totalTime += getTime() - startTime;
- if (done) showFinalStats();
- return ships;
- }
- if (turn) for (int x : ships) vs[x] = 1;
- SNO = ships.S;
- UNO = ufos.S / 3;
- if (turn == 0)
- REP(u, UNO) UFODIST[u] += PO[ufos[u*3]][ufos[u*3+1]];
- REP(u, UNO) UFODIST[u] += PO[ufos[u*3+1]][ufos[u*3+2]];
- if (turn == 0) {
- str.transport = false;
- str.hopSize = 0;
- str.forceUfo = VI(UNO, 0);
- }
- bool allHopped = true;
- REP(i, SNO) allHopped &= hopped[i] > 0;
- VI ufoFollowed(UNO, 0);
- VI shipFollowing(SNO, -1);
- int ufosUsed = 0;
- REP(u, UNO) REP(s, SNO) if (ufoFollowed[u] == 0 && shipFollowing[s] == -1 && ships[s] == ufos[3*u]) {
- ufoFollowed[u] = 1;
- shipFollowing[s] = u;
- ufosUsed++;
- break;
- }
- int planetsVisited = 0;
- for (int x : vs) planetsVisited += x;
- int planetsLeft = PNO - planetsVisited;
- bool MCHopCheck = false;
- bool MCForceUfoCheck = false;
- bool MCDisableUfoCheck = false;
- if (ufosUsed < UNO && (turn == 2 || turn == 25 || turn >= 75 && turn % 75 == 0)) {
- MCHopCheck = !allHopped;
- MCForceUfoCheck = true;
- // MCDisableUfoCheck = true;
- }
- bool hopSizeChange = false;
- if ((MCHopCheck || MCForceUfoCheck || MCDisableUfoCheck)) DB(totalTime);
- if ((MCHopCheck || MCForceUfoCheck || MCDisableUfoCheck) && totalTime < MAX_MC_TIME) {
- State state;
- state.turnsLeft = turnsLeft;
- state.vs = VI(vs, vs + PNO);
- state.ships = ships;
- state.hopped = VI(hopped, hopped+SNO);
- VC<pair<int, int>> vp(UNO); REP(i, UNO) vp[i] = MP(max(10, min(PNO / 12, (int)round((turn + 2) * PNO / UFODIST[i]))), i);
- sort(ALL(vp));
- VI origUfo(UNO);
- state.ufo = VVI(3, VI(UNO));
- state.ufow = VI(UNO);
- REP(j, 3) REP(i, UNO) state.ufo[j][i] = ufos[3*vp[i].Y+j];
- REP(i, UNO) state.ufow[i] = vp[i].X;
- REP(i, UNO) origUfo[i] = vp[i].Y;
- // if (turn <= 100 || turn - UPROBTURN > 600) {
- REP(i, UNO) UPROB[i] = genDistribution(PNO, state.ufow[i], UFO_DIST_SIZE);
- UPROBTURN = turn;
- // }
- state.ufoprob = VVI(UNO);
- REP(i, UNO) state.ufoprob[i] = UPROB[i];
- const int MAX_SIMS = 80;
- auto mcstart = getTime();
- DB(state.ufow);
- Strategy bestStr = str;
- double bv = 1e30;
- str.forceUfo = VI(UNO, 0);
- if (MCHopCheck) {
- hopSizeChange = true;
- VI hopSizes;
- if (PNO < 1200)
- hopSizes = {0, 10, 20, 35, 50, 80, 125, 200, 300, 500, 750, 1500};
- else
- hopSizes = {0, 20, 50, 125, 300, 750, 1500};
- VC<Strategy> strs(hopSizes.S);
- REP(i, hopSizes.S) {
- strs[i] = str;
- strs[i].transport = false;
- strs[i].hopSize = hopSizes[i];
- }
- VVI mcBeam;
- if (FULL_EVALUATE) {
- mcBeam = {{50, 0}};
- } else {
- mcBeam = {{20, 3}, {30, 0}};
- }
- VD av = monteCarlo(state, strs, mcBeam);
- REP(i, hopSizes.S)
- cerr << "Hop: " << hopSizes[i] << " Exp: " << av[i] << " Time Taken: " << getTime() - mcstart << endl;
- VC<pair<double, int>> vp;
- REP(i, av.S) vp.PB(MP(av[i], i));
- sort(ALL(vp));
- bv = vp[0].X;
- bestStr = strs[vp[0].Y];
- str = bestStr;
- DB(str.hopSize);
- }
- if (MCForceUfoCheck) {
- const int SIM1_NO = 10;
- const int SIM2_NO = 20;
- VVVI prob(SIM2_NO, VVI(UNO));
- REP(i, prob.S) REP(j, UNO) {
- prob[i][j] = state.ufoprob[j];
- rng.shuffle(prob[i][j], turnsLeft + 5);
- }
- double bv1 = monteCarlo(state, str, prob, 0, SIM1_NO);
- double bv2 = monteCarlo(state, str, prob, SIM1_NO, SIM2_NO);
- double bv = (bv1 + bv2) / 2;
- Strategy mcstr = str;
- bool noForce = true;
- REP(i, UNO) if ((!noForce || !ufoFollowed[i]) && !str.forceUfo[i]) {
- mcstr.forceUfo[i] = 1;
- double av1 = monteCarlo(state, mcstr, prob, 0, SIM1_NO);
- if (av1 > bv1 && !FULL_EVALUATE) {
- mcstr.forceUfo[i] = 0;
- continue;
- }
- double av2 = monteCarlo(state, mcstr, prob, SIM1_NO, SIM2_NO);
- double av = (av1 + av2) / 2;
- if (av < bv - 100) {
- bv = av;
- bv1 = av1;
- str.forceUfo[origUfo[i]] = 1;
- noForce = false;
- } else {
- mcstr.forceUfo[i] = 0;
- }
- cerr << "ForceUfo: " << i << " Exp: " << av << " Time Taken: " << getTime() - mcstart << endl;
- }
- }
- totalTime += getTime() - startTime;
- startTime = getTime();
- }
- REP(u, UNO) REP(s, SNO) if (ufoFollowed[u] == 0 && shipFollowing[s] == -1 && ships[s] == ufos[3*u+1]) {
- ufoFollowed[u] = 1;
- shipFollowing[s] = u;
- ufosUsed++;
- break;
- }
- REP(u, UNO) REP(s, SNO) if (ufoFollowed[u] == 0 && shipFollowing[s] == -1 && ships[s] == ufos[3*u+2]) {
- ufoFollowed[u] = 1;
- shipFollowing[s] = u;
- ufosUsed++;
- break;
- }
- VI rv = VI(SNO, -1);
- if (UNO == 0 || planetsLeft >= turnsLeft - 2) {
- #ifndef LOCAL
- double oldTime = totalTime;
- totalTime = 20.0 - Server::getRemainingTime(0) * 1e-3;
- cerr << "Old: " << oldTime << " vs New: " << totalTime << endl;
- #endif
- VI notVisited;
- REP(p, PNO) if (!vs[p]) notVisited.PB(p);
- REP(i, notVisited.S) swap(notVisited[i], notVisited[rng.next(i, notVisited.S)]);
- DB(greedy(ships, notVisited));
- REP(s, SNO) {
- PATHLEN[s] = 1;
- PATH[s][0] = ships[s];
- }
- REP(i, notVisited.S) PATH[i%SNO][PATHLEN[i%SNO]++] = notVisited[i];
- REP(i, SNO) PATH[i][PATHLEN[i]] = PNO;
- REP(s, SNO) {
- BPATHLEN[s] = PATHLEN[s];
- REP(i, PATHLEN[s]+1) BPATH[s][i] = PATH[s][i];
- }
- REP(i, PNO) REP(j, PNO) OPD[i][j] = PD[i][j];
- REP(s, SNO) vs[ships[s]] = 0;
- REP(i, PNO) {
- int pos = 0;
- REP(j, PNO) if (PN[i][j] != i && !vs[PN[i][j]]) {
- PC[i][pos++] = PN[i][j];
- if (pos == MAX_NEIGHBOURS) break;
- }
- }
- REP(s, SNO) vs[ships[s]] = 1;
- REP(s, SNO) updatePPOS(s, 0, PATHLEN[s]-1);
- REP(u, UNO) {
- int p = ufos[3*u];
- if (!vs[p]) continue;
- REP(i, PNO) {
- double d = OPD[p][i];
- d = min(d, OPD[ufos[3*u+1]][i]);
- d = min(d, OPD[ufos[3*u+2]][i]);
- PD[p][i] = PD[i][p] = d;
- }
- }
- cerr << "[Mode] TSP at: " << totalTime << endl;
- DB(notVisited.S);
- double bv = calcSolution();
- double xv = bv;
- VD shipCost(SNO);
- REP(i, SNO) shipCost[i] = calcSolution(i);
- int steps = 0;
- int steps2 = 0;
- int acc = 0;
- int bestacc = 0;
- double timePassed = 0.0;
- double temp = 0.0;
- int NEIGHBOURS = min(MAX_NEIGHBOURS, (int)notVisited.S);
- while (true) {
- if ((steps & 1023) == 0) {
- if (notVisited.S == 1) break;
- timePassed = (getTime() - startTime) / (TIME_LIMIT - totalTime);
- temp = (1.0 - pow(timePassed, 0.15)) * 160;//(notVisited.S < 50 ? 320 : notVisited.S < 100 ? 240 : 160);
- if (timePassed >= 1.0) break;
- }
- steps++;
- int s0 = rng.next(SNO);
- if (PATHLEN[s0] == 1) continue;
- int p0 = rng.next(1, PATHLEN[s0]);
- int mode = rng.rand() & 1;
- int p1, s1;
- if (mode == 0) {
- PII p = PPOS[PC[PATH[s0][p0]][rng.next(NEIGHBOURS)]];
- s1 = p.X;
- p1 = p.Y;
- } else {
- p1 = 0;
- s1 = rng.next(SNO);
- }
- int p0b, p1b;
- int type;
- double diff = 0;
- if (s0 == s1) {
- if (p1 == 0) p1 = rng.next(1, PATHLEN[s0]);
- type = rng.next(2) == 0;
- if (type == 0) {
- if (p0 == p1) continue;
- if (p0 > p1) swap(p0, p1);
- diff -= pathDist(s0, p0-1, PATH[s0][p0]);
- diff -= pathDist(s0, p1+1, PATH[s0][p1]);
- diff += pathDist(s0, p0-1, PATH[s0][p1]);
- diff += pathDist(s0, p1+1, PATH[s0][p0]);
- } else {
- if (abs(p0-p1)<=2) continue;
- diff -= pathDist(s0, p0-1, PATH[s0][p0]);
- diff -= pathDist(s0, p0+1, PATH[s0][p0]);
- diff += pathDist(s0, p0+1, PATH[s0][p0-1]);
- diff -= pathDist(s0, p1, PATH[s0][p1-1]);
- diff += pathDist(s0, p1-1, PATH[s0][p0]);
- diff += pathDist(s0, p1, PATH[s0][p0]);
- }
- } else {
- type = rng.next(2) == 0;
- if (type == 0) {
- if (PATHLEN[s1] == 1) continue;
- if (p1 == 0) p1 = rng.next(1, PATHLEN[s1]);
- p0b = rng.next(1, PATHLEN[s0]);
- p1b = rng.next(1, PATHLEN[s1]);
- if (p0 > p0b) swap(p0, p0b);
- if (p1 > p1b) swap(p1, p1b);
- // int move = (p0b-p0)-(p1b-p1);
- // if (PATHLEN[s0]-move>turnsLeft || PATHLEN[s1]+move>turnsLeft) continue;
- diff -= pathDist(s0, p0-1, PATH[s0][p0]);
- diff -= pathDist(s0, p0b+1, PATH[s0][p0b]);
- diff += pathDist(s0, p0-1, PATH[s1][p1]);
- diff += pathDist(s0, p0b+1, PATH[s1][p1b]);
- diff -= pathDist(s1, p1-1, PATH[s1][p1]);
- diff -= pathDist(s1, p1b+1, PATH[s1][p1b]);
- diff += pathDist(s1, p1-1, PATH[s0][p0]);
- diff += pathDist(s1, p1b+1, PATH[s0][p0b]);
- } else {
- p1 = p1 == 0 ? rng.next(1, PATHLEN[s1]+1) : p1 + 1;
- if (rng.next(2)) {
- p0b = rng.next(1, PATHLEN[s0]);
- if (p0 > p0b) swap(p0, p0b);
- } else {
- p0b = p0;
- }
- p1b = p1-1;
- // if (PATHLEN[s1]+(p0b-p0)+1>turnsLeft) continue;
- diff -= pathDist(s0, p0-1, PATH[s0][p0]);
- diff -= pathDist(s0, p0b+1, PATH[s0][p0b]);
- diff += pathDist(s0, p0b+1, PATH[s0][p0-1]);
- diff -= pathDist(s1, p1, PATH[s1][p1-1]);
- diff += pathDist(s1, p1-1, PATH[s0][p0]);
- diff += pathDist(s1, p1, PATH[s0][p0b]);
- }
- }
- if (diff <= rng.nextDouble() * temp) {
- if (s0 == s1) {
- if (type == 0) {
- reverse(PATH[s0]+p0, PATH[s0]+p1+1);
- updatePPOS(s0, p0, p1);
- } else {
- int tmp = PATH[s0][p0];
- if (p0 < p1) {
- FOR(i, p0, p1-1) PATH[s0][i] = PATH[s0][i+1];
- PATH[s0][p1-1] = tmp;
- } else {
- for (int i = p0; i > p1; i--) PATH[s0][i] = PATH[s0][i-1];
- PATH[s0][p1] = tmp;
- }
- updatePPOS(s0, p0, p1);
- }
- } else {
- if (p0b-p0>p1b-p1) {
- swap(s0, s1);
- swap(p0, p1);
- swap(p0b, p1b);
- }
- int move = (p1b-p1)-(p0b-p0);
- assert(move >= 0);
- FOR(i, p0, p0b+1) TPATH[i] = PATH[s0][i];
- PATHLEN[s0] += move;
- PATHLEN[s1] -= move;
- assert(PATHLEN[s0] <= turnsLeft+1);
- assert(PATHLEN[s1] <= turnsLeft+1);
- for (int i = PATHLEN[s0]-1; i >= p0b+1+move; i--) PATH[s0][i] = PATH[s0][i-move]; //TODO: fix
- FOR(i, p1, p1b+1) PATH[s0][i-p1+p0] = PATH[s1][i];
- FOR(i, p0, p0b+1) PATH[s1][i-p0+p1] = TPATH[i];
- FOR(i, p1b+1-move, PATHLEN[s1]) PATH[s1][i] = PATH[s1][i+move];
- updatePPOS(s0, p0, PATHLEN[s0]-1);
- updatePPOS(s1, 1, PATHLEN[s1]-1);
- }
- PATH[s0][PATHLEN[s0]] = PNO;
- PATH[s1][PATHLEN[s1]] = PNO;
- bv += diff;
- acc++;
- if (bv < xv) {
- xv = bv;
- bestacc++;
- REP(s, SNO) {
- BPATHLEN[s] = PATHLEN[s];
- REP(i, PATHLEN[s]) BPATH[s][i] = PATH[s][i];
- }
- }
- }
- }
- REP(i, PNO) REP(j, PNO) PD[i][j] = OPD[i][j];
- DB(calcSolution());
- DB(xv);
- DB(steps);
- DB(acc);
- DB(bestacc);
- DB(detours);
- FINAL_PATH = true;
- REP(s, SNO) {
- BPATHSUM[s][0] = 0;
- FOR(i, 1, BPATHLEN[s]) {
- BPATHSUM[s][i] = BPATHSUM[s][i-1] + PD[BPATH[s][i-1]][BPATH[s][i]];
- }
- }
- finalPathGain = xv;
- totalTime += getTime() - startTime;
- DB(totalTime);
- return makeMoves(ufos, ships);
- } else {
- //Wait for UFO
- bool performDetour = false;
- double mcmstEstimate = 0;
- VI upos, fpos;
- if (planetsLeft + 1200 > turnsLeft && planetsLeft < 500) {
- if (!performDetourStarted) {
- REP(i, UNO) UPROB[i] = genDistribution(PNO, max(12, min(PNO / 12, (int)round((turn + 2) * PNO / UFODIST[i]))), UFO_DIST_SIZE);
- performDetourStarted = true;
- cerr << "[Mode] Detour at: " << totalTime << endl;
- }
- UPROBTURN = turn;
- performDetour = true;
- ZERO(XVS);
- XVSNO = 1;
- REP(u, UNO) upos.PB(ufos[3*u+2]);
- REP(s, SNO) if (shipFollowing[s] == -1) fpos.PB(ships[s]);
- if (totalTime < MAX_MCMST_TIME && (planetsLeft < MCMST_MAX_PLANETS && turnsLeft - planetsLeft < MCMST_MAX_TURNS)) {
- mcmstEstimate = calcMCMST(fpos, upos, ufoFollowed, turnsLeft - planetsLeft, MCMST_SIMS);
- }
- PEXPCOST = max(50.0, 90 - (turnsLeft - planetsLeft) * 0.20);
- }
- VI usedUfo(UNO);
- rv = VI(SNO, -1);
- int ufosUsed = 0;
- if (hopSizeChange) {
- DB(VI(hopped, hopped+SNO));
- DB(str.hopSize);
- VVI w(SNO, VI(UNO, -1));
- REP(s, SNO) REP(u, UNO) {
- double minDist = 1e30;
- if (ships[s] == ufos[3*u]) minDist = 0;
- minDist = min(minDist, PD[ships[s]][ufos[3*u+1]]);
- minDist = min(minDist, PD[ships[s]][ufos[3*u+2]]);
- if (minDist > str.hopSize && !str.forceUfo[u]) continue;
- if (hopped[s] && !str.forceUfo[u] && minDist > 0) continue;
- w[s][u] = (int)round(minDist) + (str.forceUfo[u] ? 0 : 2000);
- }
- VI matching = bestMatching(w);
- REP(s, SNO) if (matching[s] != -1) {
- int u = matching[s];
- int p = ufos[3*u+1];
- if (ships[s] != ufos[3*u] && PD[ships[s]][ufos[3*u+2]] < PD[ships[s]][ufos[3*u+1]]) {
- // cerr << "Saved: " << PD[ships[s]][ufos[3*u+1]] - PD[ships[s]][ufos[3*u+2]] << endl;
- p = ships[s];
- NEXTMOVE[s] = u;
- }
- hopped[s] = 1;
- rv[s] = p;
- vs[p] = 1;
- }
- DB(VI(hopped, hopped+SNO));
- DB(matching);
- } else {
- if (mcmstEstimate && turn % 10 == 0) {
- DB(ufoFollowed);
- DB(fpos);
- cerr << "MCMST Calculate Jump" << endl;
- REP(u, UNO) if (!ufoFollowed[u]) {
- int s = rng.next(SNO);
- // REP(i, SNO) if (PD[ships[i]][ufos[3*u+1]] < PD[ships[s]][ufos[3*u+1]]) s = i;
- if (rv[s] != -1) continue;
- if (shipFollowing[s] == -1) {
- bool found = false;
- REP(i, fpos.S) if (fpos[i] == ships[s]) {
- fpos.erase(fpos.begin() + i);
- found = true;
- break;
- }
- assert(found);
- } else {
- ufoFollowed[shipFollowing[s]] = 0;
- }
- ufoFollowed[u] = 1;
- double estimate = calcMCMST(fpos, upos, ufoFollowed, turnsLeft - planetsLeft, MCMST_SIMS);
- ufoFollowed[u] = 0;
- if (shipFollowing[s] == -1) {
- fpos.PB(ships[s]);
- } else {
- ufoFollowed[shipFollowing[s]] = 1;
- }
- double dist = min(PD[ships[s]][ufos[3*u+1]], PD[ships[s]][ufos[3*u+2]]);
- if (estimate + dist < mcmstEstimate - 200) {
- ufosUsed += usedUfo[u] == 0;
- usedUfo[u] = 1;
- rv[s] = PD[ships[s]][ufos[3*u+1]] < PD[ships[s]][ufos[3*u+2]] ? ufos[3*u+1] : ufos[3*u+2];
- vs[rv[s]] = 1;
- hopped[s] = 1;
- if (shipFollowing[s] == -1) {
- bool found = false;
- REP(i, fpos.S) if (fpos[i] == ships[s]) {
- fpos.erase(fpos.begin() + i);
- found = true;
- break;
- }
- assert(found);
- } else {
- ufoFollowed[shipFollowing[s]] = 0;
- }
- ufoFollowed[u] = 1;
- shipFollowing[s] = u;
- cerr << "Performed Jump: " << mcmstEstimate << " -> " << estimate << " + " << dist << " = " << estimate + dist << endl;
- }
- }
- // cerr << "Finished Jumping" << endl;
- }
- while (true) {
- double bv = -1e30;
- int bs = -1;
- int bp = -1;
- int bu = -1;
- int bt = -1;
- REP(s, SNO) if (rv[s] == -1) {
- REP(u, UNO) if (usedUfo[u] == 0 || false && performDetour && SNO > UNO) {
- int p1 = ufos[u*3+0];
- int p2 = ufos[u*3+1];
- int p3 = ufos[u*3+2];
- double av = usedUfo[u] * -1e10;
- bool sameplanet = p1 == ships[s] || p2 == ships[s] || p3 == ships[s];
- // if (!sameplanet && usedUfo[u]) continue;
- int tp = p1 == ships[s] ? p2 : ships[s];
- if (!sameplanet) {
- double d1 = PD[ships[s]][ufos[u*3+1]];
- double d2 = PD[ships[s]][ufos[u*3+2]];
- if (min(d1, d2) > (hopped[s] ? 0 : str.hopSize)) continue;
- if (d1 < d2) {
- tp = p2;
- av += d1 * -1e6;
- } else {
- tp = -1;
- av += d2 * -1e6;
- }
- }
- av += UFODIST[u] / (turn+2) * 1e3;
- av += (p1 == ships[s]);
- if (av > bv) {
- bv = av;
- bu = u;
- bs = s;
- bp = tp;
- bt = 0;
- }
- }
- if (NEXTMOVE[s] != -1) {
- bu = NEXTMOVE[s];
- bs = s;
- bt = 0;
- if (ships[bs] == ufos[3*bu] || PD[ships[bs]][ufos[3*bu+1]] < PD[ships[bs]][ufos[3*bu+2]]) {
- bp = ufos[3*bu+1];
- NEXTMOVE[s] = -1;
- } else {
- bp = ships[bs];
- }
- break;
- }
- }
- if (bu == -1) break;
- if (performDetour && ufos[bu*3] == ships[bs] && vs[ufos[bu*3+1]] && vs[ufos[bu*3+2]]) {
- bv = 1e30;
- int xp = -1;
- REP(i, PNO) if (!vs[i]) {
- double av = min(PD[i][ships[bs]], min(PD[i][ufos[bu*3+1]], PD[i][ufos[bu*3+2]]));
- if (av < bv) {
- bv = av;
- xp = i;
- }
- }
- if (xp != -1) {
- if (mcmstEstimate && ufoFollowed[bu]) {
- ufoFollowed[bu] = 0;
- fpos.PB(xp);
- double estimate = calcMCMST(fpos, upos, ufoFollowed, turnsLeft - planetsLeft, MCMST_SIMS);
- fpos.pop_back();
- ufoFollowed[bu] = 1;
- DB(totalTime);
- DB(turn);
- DB(bu);
- DB(PEXPCOST);
- DB(bv);
- DB(estimate);
- DB(mcmstEstimate);
- if (estimate + bv > mcmstEstimate - (15 + (turnsLeft - planetsLeft) * 0.5)) {
- xp = -1;
- }
- } else if (bv < PEXPCOST) {
- int turns = turnsLeft - planetsLeft;
- const int sims = 100;
- int vis1 = 0;
- int visx = 0;
- FOR(sim, 1, sims+1) {
- XVSNO++;
- int planet = ufos[bu*3+2];
- int no = 0;
- REP(i, turns) {
- planet = PN[planet][UPROB[bu][rng.nextAnd(UFO_DIST_SIZE-1)]];
- if (!vs[planet] && XVS[planet] < XVSNO) {
- XVS[planet] = XVSNO;
- no++;
- }
- }
- vis1 += no > 0;
- visx += no;
- if (sim == 20 && (vis1 >= 20 || vis1 <= 4) || sim == 50 && (vis1 >= 48 || vis1 <= 20)) {
- vis1 = vis1 > sim / 2 ? sims : 0;
- break;
- }
- }
- if (vis1 > 0.9 * sims || visx > 1.4 * sims) xp = -1;
- } else {
- xp = -1;
- }
- }
- if (xp != -1 && PD[xp][ships[bs]] <= min(PD[xp][ufos[bu*3+1]], PD[xp][ufos[bu*3+2]])) {
- bp = xp;
- bt = 1;
- DB(bv);
- }
- }
- // detours += bt == 1;
- bp = bt == 0 && ufos[bu*3] == ships[bs] && vs[ufos[bu*3+1]] && ufos[bu*3+2] == ships[bs] ? ships[bs] : bp;
- if (bp != -1) {
- hopped[bs] = 1;
- rv[bs] = bp;
- vs[bp] = 1;
- }
- ufosUsed += usedUfo[bu] == 0;
- usedUfo[bu]++;
- if (ufosUsed == UNO && !performDetour) break;
- }
- }
- REP(i, SNO) if (rv[i] == -1) rv[i] = ships[i];
- if (false && turn % 1000 == 0) {
- DB(turn);
- DB(hops);
- REP(i, UNO)
- cerr << i << ' ' << usedUfo[i] << ' ' << UFODIST[i]*1.0/(turn+2) << endl;
- }
- }
- bool allVS = true;
- REP(i, PNO) if (!vs[i]) {
- allVS = false;
- break;
- }
- totalTime += getTime() - startTime;
- if (allVS) showFinalStats();
- return rv;
- }
- };
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement