Download docker_space/frontier_cs_5/solution.cpp from JustinTX/shinka-backup: direct link, hf CLI and curl.
- Browser
- Download file 26.7 kB
-
https://huggingface.co/JustinTX/shinka-backup/resolve/main/docker_space/frontier_cs_5/solution.cpp
- Command line
-
hf download hf://JustinTX/shinka-backup/docker_space/frontier_cs_5/solution.cpp
-
curl -L -o solution.cpp https://huggingface.co/JustinTX/shinka-backup/resolve/main/docker_space/frontier_cs_5/solution.cpp
26.7 kB
| using namespace std; | |
| struct FastScanner { | |
| static const int BUFSIZE = 1 << 20; | |
| int idx = 0, sz = 0; | |
| char buf[BUFSIZE]; | |
| inline char gc() { | |
| if (idx >= sz) { sz = (int)fread(buf, 1, BUFSIZE, stdin); idx = 0; if (!sz) return 0; } | |
| return buf[idx++]; | |
| } | |
| template<class T> bool readInt(T &out) { | |
| char c; T sign = 1; out = 0; | |
| do { c = gc(); if (!c) return false; } while (c <= ' '); | |
| if (c == '-') { sign = -1; c = gc(); } | |
| for (; c >= '0' && c <= '9'; c = gc()) out = out * 10 + (c - '0'); | |
| out *= sign; | |
| return true; | |
| } | |
| } fs; | |
| static uint64_t rngState; | |
| static inline uint64_t splitmix64() { | |
| uint64_t x = (rngState += 0x9e3779b97f4a7c15ULL); | |
| x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9ULL; | |
| x = (x ^ (x >> 27)) * 0x94d049bb133111ebULL; | |
| return x ^ (x >> 31); | |
| } | |
| static inline int randInt(int n) { return (int)(splitmix64() % n); } | |
| chrono::high_resolution_clock::time_point t0; | |
| inline double elapsed() { | |
| return chrono::duration<double>(chrono::high_resolution_clock::now() - t0).count(); | |
| } | |
| int n, m; | |
| int *adjData, *radjData; | |
| int *adjStart, *radjStart; | |
| int *degOut, *degIn; | |
| int *adjSorted; | |
| inline bool hasEdge(int u, int v) { | |
| return binary_search(adjSorted + adjStart[u], adjSorted + adjStart[u] + degOut[u], v); | |
| } | |
| vector<int> bestPath; | |
| void improvePath(vector<int>& path, double timeLim) { | |
| if (path.empty() || (int)path.size() == n) return; | |
| int *nxt = (int*)calloc(n + 1, sizeof(int)); | |
| int *prv = (int*)calloc(n + 1, sizeof(int)); | |
| char *used = (char*)calloc(n + 1, sizeof(char)); | |
| for (int v : path) used[v] = 1; | |
| for (int i = 0; i + 1 < (int)path.size(); i++) { | |
| nxt[path[i]] = path[i + 1]; | |
| prv[path[i + 1]] = path[i]; | |
| } | |
| int head = path[0], tail = path.back(); | |
| auto extendEnds = [&]() { | |
| while (true) { | |
| bool prog = false; | |
| while (true) { | |
| int best = 0; | |
| int s = adjStart[tail], l = degOut[tail]; | |
| for (int j = 0; j < l; j++) if (!used[adjData[s + j]]) { best = adjData[s + j]; break; } | |
| if (!best) break; | |
| nxt[tail] = best; prv[best] = tail; used[best] = 1; tail = best; prog = true; | |
| } | |
| while (true) { | |
| int best = 0; | |
| int s = radjStart[head], l = degIn[head]; | |
| for (int j = 0; j < l; j++) if (!used[radjData[s + j]]) { best = radjData[s + j]; break; } | |
| if (!best) break; | |
| prv[head] = best; nxt[best] = head; used[best] = 1; head = best; prog = true; | |
| } | |
| if (!prog) break; | |
| } | |
| }; | |
| auto insertionPass = [&]() -> bool { | |
| bool changed = false; | |
| int u = head; | |
| while (u) { | |
| int w = nxt[u]; | |
| if (!w) break; | |
| int s = adjStart[u], l = degOut[u]; | |
| for (int j = 0; j < l; j++) { | |
| int v = adjData[s + j]; | |
| if (!used[v] && hasEdge(v, w)) { | |
| nxt[u] = v; prv[v] = u; nxt[v] = w; prv[w] = v; | |
| used[v] = 1; changed = true; w = v; | |
| } | |
| } | |
| u = w; | |
| } | |
| return changed; | |
| }; | |
| auto reverseInsertion = [&]() -> bool { | |
| bool changed = false; | |
| for (int v = 1; v <= n; v++) { | |
| if (used[v]) continue; | |
| bool ins = false; | |
| int s = adjStart[v], l = degOut[v]; | |
| for (int j = 0; j < l && !ins; j++) { | |
| int w = adjData[s + j]; | |
| if (!used[w]) continue; | |
| int u2 = prv[w]; | |
| if (u2 && hasEdge(u2, v)) { | |
| nxt[u2] = v; prv[v] = u2; nxt[v] = w; prv[w] = v; | |
| used[v] = 1; changed = true; ins = true; | |
| } | |
| } | |
| if (ins) continue; | |
| int rs = radjStart[v], rl = degIn[v]; | |
| for (int j = 0; j < rl && !ins; j++) { | |
| int u2 = radjData[rs + j]; | |
| if (!used[u2]) continue; | |
| int w = nxt[u2]; | |
| if (w && hasEdge(v, w)) { | |
| nxt[u2] = v; prv[v] = u2; nxt[v] = w; prv[w] = v; | |
| used[v] = 1; changed = true; ins = true; | |
| } | |
| } | |
| if (ins) continue; | |
| if (hasEdge(v, head)) { | |
| prv[head] = v; nxt[v] = head; head = v; | |
| used[v] = 1; changed = true; | |
| } else if (hasEdge(tail, v)) { | |
| nxt[tail] = v; prv[v] = tail; tail = v; | |
| used[v] = 1; changed = true; | |
| } | |
| } | |
| return changed; | |
| }; | |
| extendEnds(); | |
| for (int pass = 0; pass < 30; pass++) { | |
| bool ch = insertionPass(); | |
| extendEnds(); | |
| if (!ch) break; | |
| } | |
| for (int pass = 0; pass < 30 && elapsed() < timeLim; pass++) { | |
| bool ch = reverseInsertion(); | |
| extendEnds(); | |
| insertionPass(); | |
| extendEnds(); | |
| if (!ch) break; | |
| } | |
| // 2-vertex chain insertion | |
| if (n <= 1000 && elapsed() < timeLim) { | |
| for (int pass = 0; pass < 5 && elapsed() < timeLim; pass++) { | |
| bool changed = false; | |
| for (int v1 = 1; v1 <= n && elapsed() < timeLim; v1++) { | |
| if (used[v1]) continue; | |
| bool done = false; | |
| int s1 = adjStart[v1], l1 = degOut[v1]; | |
| for (int j1 = 0; j1 < l1 && !done; j1++) { | |
| int v2 = adjData[s1 + j1]; | |
| if (used[v2] || v2 == v1) continue; | |
| int rs1 = radjStart[v1], rl1 = degIn[v1]; | |
| for (int j2 = 0; j2 < rl1 && !done; j2++) { | |
| int u = radjData[rs1 + j2]; | |
| if (!used[u]) continue; | |
| int w = nxt[u]; | |
| if (w && hasEdge(v2, w)) { | |
| nxt[u] = v1; prv[v1] = u; | |
| nxt[v1] = v2; prv[v2] = v1; | |
| nxt[v2] = w; prv[w] = v2; | |
| used[v1] = 1; used[v2] = 1; | |
| changed = true; done = true; | |
| } | |
| } | |
| // Also try: v1->v2 at head/tail | |
| if (!done && hasEdge(v2, head)) { | |
| int rs2 = radjStart[v1], rl2 = degIn[v1]; | |
| // v1 needs an in-edge from somewhere... actually just check if v1 can be at head | |
| // Nothing feeds into v1 from the path, but v1 is the new head | |
| // We need: v1 -> v2 -> head | |
| nxt[v1] = v2; prv[v2] = v1; nxt[v2] = head; prv[head] = v2; | |
| head = v1; | |
| used[v1] = 1; used[v2] = 1; | |
| changed = true; done = true; | |
| } | |
| if (!done && hasEdge(tail, v1)) { | |
| nxt[tail] = v1; prv[v1] = tail; nxt[v1] = v2; prv[v2] = v1; | |
| tail = v2; | |
| used[v1] = 1; used[v2] = 1; | |
| changed = true; done = true; | |
| } | |
| } | |
| } | |
| extendEnds(); | |
| insertionPass(); | |
| reverseInsertion(); | |
| extendEnds(); | |
| if (!changed) break; | |
| } | |
| } | |
| // Reroute: for each edge u->w in path, try u->v->w where v is unused | |
| if (n <= 1000 && elapsed() < timeLim) { | |
| for (int pass = 0; pass < 5 && elapsed() < timeLim; pass++) { | |
| bool changed = false; | |
| int u = head; | |
| while (u && elapsed() < timeLim) { | |
| int w = nxt[u]; | |
| if (!w) break; | |
| int s = adjStart[u], l = degOut[u]; | |
| bool rerouted = false; | |
| for (int j = 0; j < l && !rerouted; j++) { | |
| int v = adjData[s + j]; | |
| if (v == w || used[v]) continue; | |
| if (hasEdge(v, w)) { | |
| nxt[u] = v; prv[v] = u; nxt[v] = w; prv[w] = v; | |
| used[v] = 1; changed = true; rerouted = true; | |
| } | |
| } | |
| if (!rerouted) { | |
| // Try u -> v1 -> v2 -> w | |
| for (int j1 = 0; j1 < l && !rerouted; j1++) { | |
| int v1 = adjData[s + j1]; | |
| if (v1 == w || used[v1]) continue; | |
| int s2 = adjStart[v1], l2 = degOut[v1]; | |
| for (int j2 = 0; j2 < l2 && !rerouted; j2++) { | |
| int v2 = adjData[s2 + j2]; | |
| if (v2 == w || v2 == v1 || used[v2]) continue; | |
| if (hasEdge(v2, w)) { | |
| nxt[u] = v1; prv[v1] = u; | |
| nxt[v1] = v2; prv[v2] = v1; | |
| nxt[v2] = w; prv[w] = v2; | |
| used[v1] = 1; used[v2] = 1; | |
| changed = true; rerouted = true; | |
| } | |
| } | |
| } | |
| } | |
| u = nxt[u]; | |
| } | |
| extendEnds(); | |
| insertionPass(); | |
| reverseInsertion(); | |
| extendEnds(); | |
| if (!changed) break; | |
| } | |
| } | |
| // Vertex swap: for each unused v, try to replace a path vertex b with v | |
| // such that b can be reinserted elsewhere | |
| if (n <= 500 && elapsed() < timeLim) { | |
| for (int pass = 0; pass < 3 && elapsed() < timeLim; pass++) { | |
| bool changed = false; | |
| for (int v = 1; v <= n && elapsed() < timeLim; v++) { | |
| if (used[v]) continue; | |
| // For each path node b, try replacing b with v | |
| // Requirements: prv[b]->v and v->nxt[b] (v replaces b) | |
| // Then b is free and can be reinserted | |
| for (int b = 1; b <= n; b++) { | |
| if (!used[b]) continue; | |
| int pb = prv[b], nb = nxt[b]; | |
| if (!pb && !nb) continue; // b is alone | |
| bool canReplace = false; | |
| if (pb && nb) canReplace = hasEdge(pb, v) && hasEdge(v, nb); | |
| else if (!pb && nb) canReplace = hasEdge(v, nb); // b is head | |
| else if (pb && !nb) canReplace = hasEdge(pb, v); // b is tail | |
| if (!canReplace) continue; | |
| // Remove b, insert v in b's place | |
| if (pb) nxt[pb] = v; else head = v; | |
| if (nb) prv[nb] = v; else tail = v; | |
| prv[v] = pb; nxt[v] = nb; | |
| used[v] = 1; | |
| used[b] = 0; prv[b] = 0; nxt[b] = 0; | |
| // Try to reinsert b | |
| bool reins = false; | |
| // Try between path nodes | |
| for (int j = 0; j < degOut[b] && !reins; j++) { | |
| int w = adjData[adjStart[b] + j]; | |
| if (!used[w]) continue; | |
| int pu = prv[w]; | |
| if (pu && hasEdge(pu, b)) { | |
| nxt[pu] = b; prv[b] = pu; nxt[b] = w; prv[w] = b; | |
| used[b] = 1; reins = true; | |
| } | |
| } | |
| if (!reins) { | |
| for (int j = 0; j < degIn[b] && !reins; j++) { | |
| int u2 = radjData[radjStart[b] + j]; | |
| if (!used[u2]) continue; | |
| int w = nxt[u2]; | |
| if (w && hasEdge(b, w)) { | |
| nxt[u2] = b; prv[b] = u2; nxt[b] = w; prv[w] = b; | |
| used[b] = 1; reins = true; | |
| } | |
| } | |
| } | |
| if (!reins && hasEdge(b, head)) { | |
| prv[head] = b; nxt[b] = head; head = b; | |
| used[b] = 1; reins = true; | |
| } | |
| if (!reins && hasEdge(tail, b)) { | |
| nxt[tail] = b; prv[b] = tail; tail = b; | |
| used[b] = 1; reins = true; | |
| } | |
| if (reins) { | |
| changed = true; | |
| break; // done with v | |
| } else { | |
| // Undo: put b back, remove v | |
| if (prv[v]) nxt[prv[v]] = b; else head = b; | |
| if (nxt[v]) prv[nxt[v]] = b; else tail = b; | |
| prv[b] = prv[v]; nxt[b] = nxt[v]; | |
| used[b] = 1; | |
| used[v] = 0; prv[v] = 0; nxt[v] = 0; | |
| } | |
| } | |
| } | |
| if (changed) { | |
| extendEnds(); | |
| insertionPass(); | |
| reverseInsertion(); | |
| extendEnds(); | |
| } else break; | |
| } | |
| } | |
| path.clear(); | |
| for (int u = head; u; u = nxt[u]) { | |
| path.push_back(u); | |
| if ((int)path.size() > n) break; | |
| } | |
| free(nxt); free(prv); free(used); | |
| } | |
| vector<int> greedyPath(int start, int mode = 0) { | |
| // mode 0: first available, mode 1: Warnsdorff, mode 2: random | |
| char *used = (char*)calloc(n + 1, sizeof(char)); | |
| deque<int> path; | |
| path.push_back(start); | |
| used[start] = 1; | |
| while (true) { | |
| bool prog = false; | |
| while (true) { | |
| int t = path.back(); | |
| int best = 0; | |
| int s = adjStart[t], l = degOut[t]; | |
| if (mode == 1) { | |
| int bestScore = INT_MAX; | |
| for (int j = 0; j < l; j++) { | |
| int v = adjData[s + j]; | |
| if (!used[v]) { | |
| int cnt = 0; | |
| int vs = adjStart[v], vl = degOut[v]; | |
| for (int k = 0; k < vl; k++) if (!used[adjData[vs + k]]) cnt++; | |
| if (cnt < bestScore) { bestScore = cnt; best = v; } | |
| } | |
| } | |
| } else if (mode == 2) { | |
| // Random | |
| int cnt = 0; | |
| for (int j = 0; j < l; j++) if (!used[adjData[s + j]]) cnt++; | |
| if (cnt > 0) { | |
| int pick = randInt(cnt), k = 0; | |
| for (int j = 0; j < l; j++) if (!used[adjData[s + j]]) { if (k == pick) { best = adjData[s + j]; break; } k++; } | |
| } | |
| } else { | |
| for (int j = 0; j < l; j++) if (!used[adjData[s + j]]) { best = adjData[s + j]; break; } | |
| } | |
| if (!best) break; | |
| path.push_back(best); used[best] = 1; prog = true; | |
| } | |
| while (true) { | |
| int h = path.front(); | |
| int best = 0; | |
| int s = radjStart[h], l = degIn[h]; | |
| if (mode == 1) { | |
| int bestScore = INT_MAX; | |
| for (int j = 0; j < l; j++) { | |
| int u = radjData[s + j]; | |
| if (!used[u]) { | |
| int cnt = 0; | |
| int us = radjStart[u], ul = degIn[u]; | |
| for (int k = 0; k < ul; k++) if (!used[radjData[us + k]]) cnt++; | |
| if (cnt < bestScore) { bestScore = cnt; best = u; } | |
| } | |
| } | |
| } else if (mode == 2) { | |
| int cnt = 0; | |
| for (int j = 0; j < l; j++) if (!used[radjData[s + j]]) cnt++; | |
| if (cnt > 0) { | |
| int pick = randInt(cnt), k = 0; | |
| for (int j = 0; j < l; j++) if (!used[radjData[s + j]]) { if (k == pick) { best = radjData[s + j]; break; } k++; } | |
| } | |
| } else { | |
| for (int j = 0; j < l; j++) if (!used[radjData[s + j]]) { best = radjData[s + j]; break; } | |
| } | |
| if (!best) break; | |
| path.push_front(best); used[best] = 1; prog = true; | |
| } | |
| if (!prog) break; | |
| } | |
| vector<int> result(path.begin(), path.end()); | |
| free(used); | |
| return result; | |
| } | |
| bool dfsBacktrackFrom(int start, double timeLim, bool randomize = false) { | |
| char *used = (char*)calloc(n + 1, sizeof(char)); | |
| int *pathArr = (int*)malloc(n * sizeof(int)); | |
| int maxDeg = 0; | |
| for (int u = 1; u <= n; u++) if (degOut[u] > maxDeg) maxDeg = degOut[u]; | |
| int *nbrBuf = (int*)malloc((long long)n * (maxDeg + 1) * sizeof(int)); | |
| int *nbrCnt = (int*)malloc(n * sizeof(int)); | |
| int *nbrIdx = (int*)malloc(n * sizeof(int)); | |
| pair<int,int> *tmp = (pair<int,int>*)malloc((maxDeg + 1) * sizeof(pair<int,int>)); | |
| bool found = false; | |
| int depth = 0; | |
| pathArr[0] = start; | |
| used[start] = 1; | |
| auto computeNbrs = [&](int d) { | |
| int v = pathArr[d]; | |
| int s = adjStart[v], l = degOut[v]; | |
| int tc = 0; | |
| for (int j = 0; j < l; j++) { | |
| int w = adjData[s + j]; | |
| if (!used[w]) { | |
| int sc = 0; | |
| int ws = adjStart[w], wl = degOut[w]; | |
| for (int k = 0; k < wl; k++) if (!used[adjData[ws + k]]) sc++; | |
| if (randomize) sc = sc * 1000 + (int)(splitmix64() % 1000); | |
| tmp[tc++] = {sc, w}; | |
| } | |
| } | |
| sort(tmp, tmp + tc); | |
| long long base = (long long)d * (maxDeg + 1); | |
| for (int i = 0; i < tc; i++) nbrBuf[base + i] = tmp[i].second; | |
| nbrCnt[d] = tc; | |
| nbrIdx[d] = 0; | |
| }; | |
| computeNbrs(0); | |
| long long checks = 0; | |
| while (depth >= 0) { | |
| if (++checks % 100000 == 0 && elapsed() > timeLim) break; | |
| if (depth == n - 1) { | |
| bestPath.assign(pathArr, pathArr + n); | |
| found = true; | |
| break; | |
| } | |
| if (depth + 1 > (int)bestPath.size()) { | |
| bestPath.assign(pathArr, pathArr + depth + 1); | |
| } | |
| bool went_deeper = false; | |
| long long base = (long long)depth * (maxDeg + 1); | |
| while (nbrIdx[depth] < nbrCnt[depth]) { | |
| int w = nbrBuf[base + nbrIdx[depth]]; | |
| nbrIdx[depth]++; | |
| if (used[w]) continue; | |
| depth++; | |
| pathArr[depth] = w; | |
| used[w] = 1; | |
| computeNbrs(depth); | |
| went_deeper = true; | |
| break; | |
| } | |
| if (!went_deeper) { | |
| used[pathArr[depth]] = 0; | |
| depth--; | |
| } | |
| } | |
| free(used); free(pathArr); free(nbrBuf); free(nbrCnt); free(nbrIdx); free(tmp); | |
| return found; | |
| } | |
| vector<int> dpOnOrder(const vector<int>& order) { | |
| vector<int> pos(n + 1), dp(n + 1, 1), par(n + 1, 0); | |
| for (int i = 0; i < n; i++) pos[order[i]] = i; | |
| for (int i = 0; i < n; i++) { | |
| int v = order[i]; | |
| int s = adjStart[v], l = degOut[v]; | |
| for (int j = 0; j < l; j++) { | |
| int w = adjData[s + j]; | |
| if (pos[w] > i && dp[v] + 1 > dp[w]) { | |
| dp[w] = dp[v] + 1; | |
| par[w] = v; | |
| } | |
| } | |
| } | |
| int bestV = 1, bestLen = dp[1]; | |
| for (int v = 2; v <= n; v++) if (dp[v] > bestLen) { bestLen = dp[v]; bestV = v; } | |
| vector<int> path; | |
| int cur = bestV; | |
| while (cur) { path.push_back(cur); cur = par[cur]; } | |
| reverse(path.begin(), path.end()); | |
| return path; | |
| } | |
| int main() { | |
| rngState = chrono::high_resolution_clock::now().time_since_epoch().count(); | |
| t0 = chrono::high_resolution_clock::now(); | |
| fs.readInt(n); fs.readInt(m); | |
| for (int i = 0; i < 10; i++) { int x; fs.readInt(x); } | |
| adjStart = (int*)calloc(n + 1, sizeof(int)); | |
| radjStart = (int*)calloc(n + 1, sizeof(int)); | |
| degOut = (int*)calloc(n + 1, sizeof(int)); | |
| degIn = (int*)calloc(n + 1, sizeof(int)); | |
| int *edgeU = (int*)malloc(m * sizeof(int)); | |
| int *edgeV = (int*)malloc(m * sizeof(int)); | |
| for (int i = 0; i < m; i++) { | |
| fs.readInt(edgeU[i]); fs.readInt(edgeV[i]); | |
| degOut[edgeU[i]]++; | |
| degIn[edgeV[i]]++; | |
| } | |
| for (int u = 1; u <= n; u++) { | |
| adjStart[u] = (u == 1) ? 0 : adjStart[u - 1] + degOut[u - 1]; | |
| radjStart[u] = (u == 1) ? 0 : radjStart[u - 1] + degIn[u - 1]; | |
| } | |
| adjData = (int*)malloc(m * sizeof(int)); | |
| radjData = (int*)malloc(m * sizeof(int)); | |
| { | |
| int *ac = (int*)malloc((n + 1) * sizeof(int)); | |
| int *rc = (int*)malloc((n + 1) * sizeof(int)); | |
| for (int u = 1; u <= n; u++) { ac[u] = adjStart[u]; rc[u] = radjStart[u]; } | |
| for (int i = 0; i < m; i++) { | |
| adjData[ac[edgeU[i]]++] = edgeV[i]; | |
| radjData[rc[edgeV[i]]++] = edgeU[i]; | |
| } | |
| free(ac); free(rc); | |
| } | |
| free(edgeU); free(edgeV); | |
| adjSorted = (int*)malloc(m * sizeof(int)); | |
| memcpy(adjSorted, adjData, m * sizeof(int)); | |
| for (int u = 1; u <= n; u++) { | |
| sort(adjSorted + adjStart[u], adjSorted + adjStart[u] + degOut[u]); | |
| } | |
| if (n <= 200) { | |
| // Small graph: DFS + many random greedy + improve | |
| // Phase 1: Deterministic DFS from best starts | |
| { | |
| vector<pair<int,int>> starts; | |
| for (int u = 1; u <= n; u++) starts.push_back({-(degOut[u] - degIn[u]), u}); | |
| sort(starts.begin(), starts.end()); | |
| bool found = false; | |
| for (int i = 0; i < (int)starts.size() && elapsed() < 0.8 && !found; i++) { | |
| double rem = 0.8 - elapsed(); | |
| double t = max(rem / ((int)starts.size() - i), 0.01); | |
| found = dfsBacktrackFrom(starts[i].second, elapsed() + t, false); | |
| } | |
| // Phase 1b: Randomized DFS - many restarts | |
| if (!found) { | |
| while (elapsed() < 2.0 && (int)bestPath.size() < n) { | |
| int sv = randInt(n) + 1; | |
| found = dfsBacktrackFrom(sv, elapsed() + 0.1, true); | |
| if (found) break; | |
| } | |
| } | |
| } | |
| // After DFS, try to improve immediately if we have a good path | |
| if ((int)bestPath.size() >= n * 3 / 4 && (int)bestPath.size() < n) { | |
| improvePath(bestPath, min(elapsed() + 1.0, 3.0)); | |
| } | |
| if ((int)bestPath.size() < n) { | |
| // Phase 2: Warnsdorff greedy from all starts | |
| for (int s = 1; s <= n && elapsed() < 2.5; s++) { | |
| auto path = greedyPath(s, 1); | |
| if ((int)path.size() > (int)bestPath.size()) bestPath = move(path); | |
| if ((int)bestPath.size() == n) break; | |
| } | |
| } | |
| if ((int)bestPath.size() < n) { | |
| // Phase 3: Shuffled greedy | |
| while (elapsed() < 3.0 && (int)bestPath.size() < n) { | |
| for (int u = 1; u <= n; u++) { | |
| int s = adjStart[u], l = degOut[u]; | |
| for (int i = l - 1; i > 0; i--) { int j = splitmix64() % (i + 1); swap(adjData[s + i], adjData[s + j]); } | |
| s = radjStart[u]; l = degIn[u]; | |
| for (int i = l - 1; i > 0; i--) { int j = splitmix64() % (i + 1); swap(radjData[s + i], radjData[s + j]); } | |
| } | |
| int sv = randInt(n) + 1; | |
| auto path = greedyPath(sv, 2); | |
| if ((int)path.size() > (int)bestPath.size()) bestPath = move(path); | |
| if ((int)bestPath.size() == n) break; | |
| path = greedyPath(sv, 0); | |
| if ((int)path.size() > (int)bestPath.size()) bestPath = move(path); | |
| } | |
| } | |
| // Phase 4: Final improvement | |
| if ((int)bestPath.size() < n && !bestPath.empty()) | |
| improvePath(bestPath, 3.8); | |
| } else { | |
| // Large graph: DP + greedy + improve | |
| { | |
| vector<int> order(n); | |
| for (int i = 0; i < n; i++) order[i] = i + 1; | |
| auto tryOrder = [&](vector<int>& ord) { | |
| auto path = dpOnOrder(ord); | |
| if ((int)path.size() > (int)bestPath.size()) bestPath = path; | |
| }; | |
| sort(order.begin(), order.end(), [&](int x, int y) { | |
| int a = degOut[x] - degIn[x], b = degOut[y] - degIn[y]; | |
| return a != b ? a > b : x < y; | |
| }); | |
| tryOrder(order); | |
| sort(order.begin(), order.end(), [&](int x, int y) { | |
| return degOut[x] != degOut[y] ? degOut[x] > degOut[y] : x < y; | |
| }); | |
| tryOrder(order); | |
| for (int iter = 0; elapsed() < 1.0 && (int)bestPath.size() < n; iter++) { | |
| for (size_t i = n - 1; i > 0; --i) { size_t j = splitmix64() % (i + 1); swap(order[i], order[j]); } | |
| tryOrder(order); | |
| } | |
| } | |
| if ((int)bestPath.size() < n && !bestPath.empty()) | |
| improvePath(bestPath, 1.5); | |
| { | |
| vector<int> starts; | |
| int best = 1; | |
| for (int u = 2; u <= n; u++) if (degOut[u] - degIn[u] > degOut[best] - degIn[best]) best = u; | |
| starts.push_back(best); | |
| best = 1; | |
| for (int u = 2; u <= n; u++) if (degIn[u] < degIn[best]) best = u; | |
| starts.push_back(best); | |
| for (int i = 0; i < 50; i++) starts.push_back(randInt(n) + 1); | |
| for (int s : starts) { | |
| if (elapsed() > 2.5 || (int)bestPath.size() == n) break; | |
| auto path = greedyPath(s, 1); | |
| if ((int)path.size() > (int)bestPath.size()) bestPath = move(path); | |
| if ((int)bestPath.size() == n) break; | |
| path = greedyPath(s, 0); | |
| if ((int)path.size() > (int)bestPath.size()) bestPath = move(path); | |
| } | |
| } | |
| if ((int)bestPath.size() < n && !bestPath.empty()) | |
| improvePath(bestPath, 3.0); | |
| if ((int)bestPath.size() < n) { | |
| while (elapsed() < 3.5 && (int)bestPath.size() < n) { | |
| for (int u = 1; u <= n; u++) { | |
| int s = adjStart[u], l = degOut[u]; | |
| for (int i = l - 1; i > 0; i--) { int j = splitmix64() % (i + 1); swap(adjData[s + i], adjData[s + j]); } | |
| s = radjStart[u]; l = degIn[u]; | |
| for (int i = l - 1; i > 0; i--) { int j = splitmix64() % (i + 1); swap(radjData[s + i], radjData[s + j]); } | |
| } | |
| auto path = greedyPath(randInt(n) + 1, 0); | |
| if ((int)path.size() > (int)bestPath.size()) { | |
| bestPath = move(path); | |
| if ((int)bestPath.size() < n) improvePath(bestPath, min(elapsed() + 0.3, 3.7)); | |
| } | |
| } | |
| } | |
| } | |
| if (bestPath.empty()) bestPath.push_back(1); | |
| printf("%d\n", (int)bestPath.size()); | |
| for (int i = 0; i < (int)bestPath.size(); i++) { | |
| if (i) putchar(' '); | |
| printf("%d", bestPath[i]); | |
| } | |
| putchar('\n'); | |
| return 0; | |
| } | |