結果
問題 | No.5015 Escape from Labyrinth |
ユーザー | Jiro_tech15 |
提出日時 | 2023-04-15 16:26:34 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 19,885 bytes |
コンパイル時間 | 4,731 ms |
コンパイル使用メモリ | 217,284 KB |
実行使用メモリ | 167,268 KB |
スコア | 0 |
最終ジャッジ日時 | 2023-04-15 16:31:16 |
合計ジャッジ時間 | 281,718 ms |
ジャッジサーバーID (参考情報) |
judge16 / judge11 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | WA | - |
testcase_01 | WA | - |
testcase_02 | WA | - |
testcase_03 | WA | - |
testcase_04 | WA | - |
testcase_05 | WA | - |
testcase_06 | WA | - |
testcase_07 | WA | - |
testcase_08 | WA | - |
testcase_09 | WA | - |
testcase_10 | WA | - |
testcase_11 | WA | - |
testcase_12 | WA | - |
testcase_13 | WA | - |
testcase_14 | WA | - |
testcase_15 | WA | - |
testcase_16 | WA | - |
testcase_17 | WA | - |
testcase_18 | WA | - |
testcase_19 | WA | - |
testcase_20 | WA | - |
testcase_21 | WA | - |
testcase_22 | WA | - |
testcase_23 | WA | - |
testcase_24 | WA | - |
testcase_25 | WA | - |
testcase_26 | WA | - |
testcase_27 | WA | - |
testcase_28 | WA | - |
testcase_29 | WA | - |
testcase_30 | WA | - |
testcase_31 | WA | - |
testcase_32 | WA | - |
testcase_33 | WA | - |
testcase_34 | WA | - |
testcase_35 | WA | - |
testcase_36 | WA | - |
testcase_37 | WA | - |
testcase_38 | WA | - |
testcase_39 | WA | - |
testcase_40 | WA | - |
testcase_41 | WA | - |
testcase_42 | WA | - |
testcase_43 | WA | - |
testcase_44 | WA | - |
testcase_45 | WA | - |
testcase_46 | WA | - |
testcase_47 | WA | - |
testcase_48 | WA | - |
testcase_49 | WA | - |
testcase_50 | WA | - |
testcase_51 | WA | - |
testcase_52 | WA | - |
testcase_53 | WA | - |
testcase_54 | WA | - |
testcase_55 | WA | - |
testcase_56 | WA | - |
testcase_57 | WA | - |
testcase_58 | WA | - |
testcase_59 | WA | - |
testcase_60 | WA | - |
testcase_61 | WA | - |
testcase_62 | WA | - |
testcase_63 | WA | - |
testcase_64 | WA | - |
testcase_65 | WA | - |
testcase_66 | WA | - |
testcase_67 | WA | - |
testcase_68 | WA | - |
testcase_69 | WA | - |
testcase_70 | WA | - |
testcase_71 | WA | - |
testcase_72 | WA | - |
testcase_73 | WA | - |
testcase_74 | WA | - |
testcase_75 | WA | - |
testcase_76 | WA | - |
testcase_77 | WA | - |
testcase_78 | WA | - |
testcase_79 | WA | - |
testcase_80 | WA | - |
testcase_81 | WA | - |
testcase_82 | WA | - |
testcase_83 | WA | - |
testcase_84 | WA | - |
testcase_85 | WA | - |
testcase_86 | WA | - |
testcase_87 | WA | - |
testcase_88 | WA | - |
testcase_89 | WA | - |
testcase_90 | WA | - |
testcase_91 | WA | - |
testcase_92 | WA | - |
testcase_93 | WA | - |
testcase_94 | WA | - |
testcase_95 | WA | - |
testcase_96 | WA | - |
testcase_97 | WA | - |
testcase_98 | WA | - |
testcase_99 | WA | - |
コンパイルメッセージ
main.cpp: メンバ関数 ‘std::vector<Pos> Solver::Solve(int)’ 内: main.cpp:798:3: 警告: 制御が非 void 関数の終りに到達しました [-Wreturn-type] 798 | } | ^ main.cpp: 静的メンバ関数 ‘static void Pos::StaticInit(int)’ 内: main.cpp:390:24: 警告: ‘dir’ may be used uninitialized [-Wmaybe-uninitialized] 390 | move_to[dir][p] = {adj_x, adj_y}; | ^ main.cpp:377:17: 備考: ‘dir’ はここで宣言されています 377 | Dir dir; | ^~~
ソースコード
namespace atcoder {} #ifdef LOCAL #define dbg(x) cerr << __LINE__ << " : " << #x << " = " << (x) << endl; #else #define NDEBUG #define dbg(x) true; #pragma GCC target("avx2") #pragma GCC optimize("O3") #pragma GCC optimize("unroll-loops") #endif #ifdef GTEST #include <gtest/gtest.h> #endif #include <math.h> #include <algorithm> #include <array> #include <bitset> #include <cassert> #include <chrono> #include <cstdlib> #include <cstring> #include <functional> #include <iomanip> #include <iostream> #include <limits> #include <list> #include <map> #include <numeric> #include <queue> #include <set> #include <sstream> #include <stack> #include <string> #include <tuple> #include <unordered_map> #include <unordered_set> #include <vector> #ifdef PERF #include <gperftools/profiler.h> #endif using namespace std; using namespace atcoder; #define fast_io \ ios_base::sync_with_stdio(false); \ cin.tie(0); \ cout.tie(0); #define ll long long int #define rep(i, n) for (int i = 0; i < (int)(n); i++) #define reps(i, n) for (int i = 1; i <= (int)(n); i++) #define REP(i, n) for (int i = n - 1; i >= 0; i--) #define REPS(i, n) for (int i = n; i > 0; i--) #define MOD (long long int)(1e9 + 7) #define INF (int)(1e9) #define LINF (long long int)(1e18) #define chmax(a, b) a = (((a) < (b)) ? (b) : (a)) #define chmin(a, b) a = (((a) > (b)) ? (b) : (a)) #define all(v) v.begin(), v.end() typedef pair<int, int> Pii; typedef pair<ll, ll> Pll; constexpr double PI = acos(-1); #ifdef NDEBUG #define CHECK(v1, op, v2) #else #define CHECK(v1, op, v2) \ if (!((v1)op(v2))) { \ cerr << "ERROR:" << (v1) << " " << (v2) << endl; \ assert((v1)op(v2)); \ } #endif long double nCr(const int n, const int r) { long double ret = 1; rep(t, r) { ret *= (n - t); ret /= (r - t); } return ret; } template <typename T> string to_string(const vector<T>& vec) { string ret = ""; rep(i, vec.size()) { ret += vec[i].to_string(); if (i + 1 != vec.size()) { ret += ","; } } return ret; } template <typename T> ostream& operator<<(ostream& os, const vector<T>& vec) { os << to_string(vec); return os; } uint32_t xorshift() { static uint32_t x = 12345789; static uint32_t y = 362436069; static uint32_t z = 521288629; static uint32_t w = 88675123; uint32_t t; t = x ^ (x << 11); x = y; y = z; z = w; w ^= t ^ (t >> 8) ^ (w >> 19); return w; } int rand(const uint32_t l, const uint32_t r) { return xorshift() % (r - l) + l; } uint32_t rand_other_than(const uint32_t l, const uint32_t r, const uint32_t other) { const uint32_t num = rand(l, r - 1); return num + (num >= other); } template <typename T> const T& rand_vec(const vector<T>& vec) { assert(vec.size() > 0); return vec[rand(0, vec.size())]; } template <typename T> void shuffle(vector<T>& vec) { rep(l, (int)vec.size() - 1) { const int idx = rand(l, vec.size()); swap(vec[idx], vec[l]); } } class Timer { chrono::system_clock::time_point _start, _end; ll _sum = 0, _count = 0; public: void start() { _start = chrono::system_clock::now(); } void stop() { _end = chrono::system_clock::now(); } void add() { const chrono::system_clock::time_point now = chrono::system_clock::now(); _sum += static_cast<double>( chrono::duration_cast<chrono::nanoseconds>(now - _start).count()); _count++; } ll sum() const { return _sum / 1000; } int count() const { return _count; } string average() const { if (_count == 0) { return "NaN"; } return to_string(_sum / 1000 / _count); } void reset() { _start = chrono::system_clock::now(); _sum = 0; _count = 0; } inline int ms() const { const chrono::system_clock::time_point now = chrono::system_clock::now(); return static_cast<double>( chrono::duration_cast<chrono::microseconds>(now - _start).count() / 1000); } inline int ns() const { const chrono::system_clock::time_point now = chrono::system_clock::now(); return static_cast<double>( chrono::duration_cast<chrono::microseconds>(now - _start).count()); } }; #ifdef LOCAL struct Timers : unordered_map<string, Timer> { friend ostream& operator<<(ostream& os, const Timers& timers) { for (const auto& pa : timers) { os << pa.first << " time: " << pa.second.sum() / 1000 << " count: " << pa.second.count() << endl; } return os; } }; #else struct Timers { struct Dummy { void start() const {} void add() const {} }; Dummy dummy; const Dummy& operator[](const std::string& str) { return dummy; } friend ostream& operator<<(ostream& os, const Timers& timers) { return os; } }; #endif Timers global_timers; // NBD = neighborhood template <class Solution, class NBDGenerator> struct SimulatedAnnealing { public: SimulatedAnnealing(double end_time, double start_temp, double end_temp) : end_time_(end_time), inv_time_(1.0 / end_time_), cur_time_(0.0), start_temp_(start_temp), end_temp_(end_temp), diff_temp_(end_temp - start_temp), cur_temp_(start_temp) { timer_.start(); } Solution run(const Solution& initial_sol, NBDGenerator& nbd_generator) { Solution sol(initial_sol); int acc = 0; int g = 0; for (;; ++g) { // if (g % 10000 == 0) { // cout << sol.Eval() << " " << sol.Score() << endl; // cout << sol.Convert() << endl << endl; // } if ((g & 0xf) == 0) { #ifdef SA_MAX_G if (g >= SA_MAX_G) { break; } #endif UpdateTime(); UpdateTemp(); if (cur_time_ > end_time_) { break; } } // const auto prev_sol = sol; const auto nbd = nbd_generator.Generate(&sol, g); constexpr int mod = 1'000'000'000; const int r = rand(0, mod); if (static_cast<double>(r) / mod < exp(-nbd->Diff() / cur_temp_)) { acc++; nbd->Update(&sol); } else { // const auto mid_sol = sol; nbd->Restore(&sol); // if (prev_sol != sol) { // for (const auto& obj : prev_sol.pos_pairs) { // cerr << obj.Idx() << " "; // } // for (const auto& obj : mid_sol.pos_pairs) { // cerr << obj.Idx() << " "; // } // for (const auto& obj : sol.pos_pairs) { // cerr << obj.Idx() << " "; // } // abort(); // } } } cerr << "g,acc: " << g << " " << acc << endl; return sol; } private: double end_time_, inv_time_, cur_time_; double start_temp_, end_temp_, diff_temp_, cur_temp_; Timer timer_; void UpdateTime() { cur_time_ = timer_.ms(); } void UpdateTemp() { cur_temp_ = max(0.0, start_temp_ - cur_time_ * diff_temp_ * inv_time_); } }; enum Dir { // y-1, y+1, x-1, x+1 kU, kD, kL, kR }; struct Pos { int idx_; Pos() {} explicit Pos(const int _idx) : idx_(_idx) {} Pos(int _x, int _y) : idx_(_y * N + _x) { assert(N > 0); } int X() const { return pos_2_x[*this]; } int Y() const { return pos_2_y[*this]; } int Idx() const { return idx_; } operator int() const { return Idx(); } operator size_t() const { return Idx(); } const vector<Pos>& Adj() const { return adj_poses[*this]; } const vector<Dir>& AdjDirs() const { return adj_dirs[*this]; } int Manhattan(const Pos& other) const { return abs(X() - other.X()) + abs(Y() - other.Y()); } bool Move(const Dir dir) { if (move_to[dir][*this].IsDummy()) { return false; } else { *this = move_to[dir][*this]; return true; } } bool operator<(const Pos& other) const { return this->Idx() < other.Idx(); } bool operator==(const Pos& other) const { return this->Idx() == other.Idx(); } bool operator!=(const Pos& other) const { return this->Idx() != other.Idx(); } friend ostream& operator<<(ostream& os, const Pos& pos) { os << pos.X() << " " << pos.Y(); return os; } bool IsDummy() const { return this->idx_ < 0; } static Pos Dummy() { Pos p; p.idx_ = -1; return p; } static Pos TryCreate(const int x, const int y, const int z) { if (y < 0 || y >= N || x < 0 || x >= N) { return Pos::Dummy(); } else { return Pos(x, y); } } static void StaticInit(const int n) { N = n; N2 = N * N; N4 = N2 * N2; adj_poses = vector<vector<Pos>>(N2); adj_dirs = vector<vector<Dir>>(N2); move_to = vector<vector<Pos>>(4, vector<Pos>(N2, Pos::Dummy())); pos_2_y.resize(N2); pos_2_x.resize(N2); rep(y, N) { rep(x, N) { const Pos p{x, y}; pos_2_y[p] = y; pos_2_x[p] = x; for (int dy = -1; dy <= 1; ++dy) { for (int dx = -1; dx <= 1; ++dx) { if (abs(dy) + abs(dx) != 1) continue; const int adj_y = y + dy; const int adj_x = x + dx; if (adj_y < 0 || adj_y >= N) continue; if (adj_x < 0 || adj_x >= N) continue; adj_poses[p].emplace_back(adj_x, adj_y); Dir dir; if (dy == -1) { dir = kU; } else if (dy == 1) { dir = kD; } else if (dx == -1) { dir = kL; } else if (dx == 1) { dir = kR; } else { assert(false); } move_to[dir][p] = {adj_x, adj_y}; adj_dirs[p].emplace_back(dir); } } } } } static int N, N2, N4; static vector<vector<Pos>> adj_poses; static vector<vector<Dir>> adj_dirs; static vector<vector<Pos>> move_to; static vector<int> pos_2_x, pos_2_y; }; vector<vector<Pos>> Pos::adj_poses; vector<vector<Dir>> Pos::adj_dirs; vector<vector<Pos>> Pos::move_to; vector<int> Pos::pos_2_x, Pos::pos_2_y; int Pos::N, Pos::N2, Pos::N4; /* start */ template <typename Point, typename Dist> class Graph_T { public: struct Edge { Point to; Dist dist; Edge(const Point _to, const Dist _dist) : to(_to), dist(_dist) {} }; explicit Graph_T(const int n) : n_(n), adjs_(n) {} int N() const { return n_; } void AddEdge(const Point a, const Point b, const Dist dist) { adjs_[a].emplace_back(b, dist); } const vector<Edge>& Adj(const Point a) const { return adjs_[a]; } void RemoveEdge(const Point a, const Point b) { { const auto itr = std::find_if( all(adjs_[a]), [&](const Edge& edge) { return edge.to == b; }); adjs_[a].erase(itr); } } private: int n_; vector<vector<Edge>> adjs_; }; template <typename Point, typename Dist> struct DijkstraData { Dist dist = 1e9; Point prev; }; template <class Graph, typename Point, typename Dist> vector<DijkstraData<Point, Dist>> Dijkstra(const Graph& graph, const Point& base_point) { vector<DijkstraData<Point, Dist>> datas(graph.N()); using P = tuple<Dist, Point, Point>; priority_queue<P, vector<P>, greater<P>> pq; datas[base_point] = {0, base_point}; pq.emplace(0, base_point, base_point); while (pq.size() > 0) { const auto [dist, point, prev_point] = pq.top(); pq.pop(); if (datas[point].dist < dist) continue; for (const auto& edge : graph.Adj(point)) { const Point to = edge.to; const Dist edge_dist = edge.dist; const Dist new_dist = dist + edge_dist; if (datas[to].dist > new_dist) { datas[to].dist = new_dist; datas[to].prev = point; pq.emplace(new_dist, to, point); } } } return datas; } template <typename Point, typename Dist> vector<Point> Keiro(const vector<DijkstraData<Point, Dist>>& dijkstra_results, const Point& from, const Point& to) { // 到達可能であることは仮定 vector<Point> ret; Point p = to; while (p != from) { ret.emplace_back(p); p = dijkstra_results[p].prev; } ret.emplace_back(from); reverse(all(ret)); return ret; } /* start */ struct Board { using Graph = Graph_T<Pos, float>; Board() {} Board(istream& is) { is >> N >> D >> H; Pos::StaticInit(N); rep(i, N) { string s; is >> s; S += s; } is >> M; rep(i, M) { int y, x, d; is >> y >> x >> d; Tanchiki tanchiki{Pos(x, y), d}; tanchikies_.emplace_back(tanchiki); } rep(idx, Pos::N2) { const Pos p(idx); if (S[p] == 'S') { start_pos = p; } else if (S[p] == 'G') { goal_pos = p; } else if (S[p] == 'K') { key_pos = p; } else if (S[p] == 'J') { jewel_count++; } if (IsCheckPoint(p)) { check_points.emplace_back(p); } } InitBeamCount(); InitDist(); } void InitBeamCount() { pm2beams_.resize(Pos::N2, vector<int>(60)); for (const auto& tanchiki : tanchikies_) { for (const auto dir : {kU, kD, kL, kR}) { Pos p = tanchiki.p; while (p.Move(dir) && CanMove(p)) { rep(t, 60) { if (t % tanchiki.d == 0) { pm2beams_[p][t]++; } } } } } } void InitDist() { Graph graph(Pos::N2); rep(idx1, Pos::N2) { const Pos p1(idx1); if (!CanMove(p1)) continue; for (const auto& p2 : p1.Adj()) { if (!CanMove(p2)) continue; float expected_hps = std::accumulate(all(pm2beams_[p2]), 0) * D / 60.0 + 1.0; graph.AddEdge(p1, p2, expected_hps); } } dists_.resize(Pos::N2); keiros_.resize(Pos::N2); rep(idx1, Pos::N2) { const Pos p1(idx1); if (!IsCheckPoint(p1)) continue; dists_[idx1].resize(Pos::N2, INF); keiros_[idx1].resize(Pos::N2); const auto ret = Dijkstra<Graph, Pos, float>(graph, p1); rep(idx2, Pos::N2) { const Pos p2(idx2); if (!IsCheckPoint(p2)) continue; const auto& [dist, _] = ret[idx2]; dists_[idx1][idx2] = dist; if (dist < INF * 0.1) { keiros_[idx1][idx2] = ::Keiro(ret, p1, p2); } } } } bool IsCheckPoint(const Pos& p) const { // TODO: Fも追加 return S[p] == 'S' || S[p] == 'G' || S[p] == 'K' || S[p] == 'J'; } int BeamCount(const Pos& p, const int t) const { return pm2beams_[p][t % 60]; } bool CanMove(const Pos& p) const { return S[p] != '#' && S[p] != 'B' && S[p] != 'E'; } float Dist(const Pos& p1, const Pos& p2) const { return dists_[p1][p2]; } const vector<Pos>& Keiro(const Pos& from, const Pos& to) const { return keiros_[from][to]; } // 消費したHPを返す int Simulate(const vector<Pos>& poses, int t) const { // posesはSとGも含む int hp = (int)poses.size() - 1; reps(i, (int)poses.size() - 1) { const auto& p = poses[i]; hp += pm2beams_[p][(t + i) % 60] * D; } return hp; } static vector<Pos> Merge(const vector<vector<Pos>>& keiros) { assert(keiros.size() > 0); vector<Pos> ret; for (const auto& kerio : keiros) { assert(kerio.size() > 0); ret.insert(ret.end(), kerio.begin(), kerio.begin() + ((int)kerio.size() - 1)); } ret.emplace_back(keiros.back().back()); return ret; } // public int N, D, H, M; string S; Pos start_pos, goal_pos, key_pos; int jewel_count = 0; // private struct Tanchiki { Pos p; int d; }; vector<vector<float>> dists_; vector<vector<vector<Pos>>> keiros_; vector<Tanchiki> tanchikies_; vector<Pos> check_points; // [pos][mod] vector<vector<int>> pm2beams_; }; ostream& operator<<(ostream& os, const vector<Pos> keiro) { rep(i, (int)keiro.size() - 1) { const Pos from = keiro[i]; const Pos to = keiro[i + 1]; if (from == to) { os << "S"; } else if (from.Y() - 1 == to.Y()) { os << "M U"; } else if (from.Y() + 1 == to.Y()) { os << "M D"; } else if (from.X() - 1 == to.X()) { os << "M L"; } else if (from.X() + 1 == to.X()) { os << "M R"; } if (i != (int)keiro.size()) { os << "\n"; } } return os; } /* start */ Board global_board; struct Individual { vector<Pos> points; float hp = INF; bitset<3600> exists = 0; float DiffInsert(const Board& board, const int idx, const Pos& pos) const { assert(idx >= 1); assert(idx < (int)points.size()); return board.Dist(points[idx - 1], pos) + board.Dist(pos, points[idx]); } void Insert(const Board& board, const int idx, const Pos& pos) { hp += DiffInsert(board, idx, pos); points.insert(points.begin() + idx, pos); exists[pos] = true; } }; struct Population { vector<Individual> inds; Population(const Board& board) : inds(board.jewel_count + 2) { inds[3].points = vector<Pos>{board.start_pos, board.key_pos, board.goal_pos}; inds[3].hp = board.Dist(board.start_pos, board.key_pos) + board.Dist(board.key_pos, board.goal_pos); inds[3].exists[board.start_pos] = true; inds[3].exists[board.key_pos] = true; inds[3].exists[board.goal_pos] = true; } }; struct NBD { float Diff() const { return diff_; } virtual void Update(Population*) const = 0; void Restore(Population*) const {} float diff_; }; struct NBD_insert : public NBD { NBD_insert() {} NBD_insert(Population* const sol, const int ind_idx, const int insert_idx, const Pos& p) { ind_idx_ = ind_idx; insert_idx_ = insert_idx; p_ = p; const auto& ind = sol->inds[ind_idx]; assert(!ind.exists[p]); diff_ = ind.DiffInsert(global_board, insert_idx, p) + ind.hp - sol->inds[ind_idx + 1].hp; } void Update(Population* sol) const override { auto ind = sol->inds[ind_idx_]; ind.Insert(global_board, insert_idx_, p_); sol->inds[ind_idx_ + 1] = ind; } int ind_idx_; int insert_idx_; Pos p_; }; struct NBDGenerator { NBDGenerator() {} NBD* Generate(Population* const sol, const int g) { int ind_idx = rand(0, sol->inds.size()); while (sol->inds[ind_idx].hp == INF) { ind_idx = rand(0, sol->inds.size()); } while (true) { // insert const int insert_idx = rand(1, sol->inds[ind_idx].points.size()); const Pos p = rand_vec(global_board.check_points); if (sol->inds[ind_idx].exists[p]) continue; nbd_insert0 = NBD_insert(sol, ind_idx, insert_idx, p); return &nbd_insert0; } } NBD_insert nbd_insert0; }; class Solver { public: explicit Solver(istream& is) : board_(is) { global_board = board_; } vector<Pos> Solve(int time_limit) { Timer timer; timer.start(); NBDGenerator nbd_generator; time_limit -= timer.ms(); SimulatedAnnealing<Population, NBDGenerator> sa(time_limit - 300, 0.3, 0.1); Population initial_pop(board_); auto best_pop = sa.run(initial_pop, nbd_generator); REP(i, best_pop.inds.size()) { vector<vector<Pos>> keiros; const auto& ind = best_pop.inds[i]; if (ind.hp == INF) continue; rep(j, (int)ind.points.size() - 1) { auto keiro = board_.Keiro(ind.points[j], ind.points[j + 1]); keiros.emplace_back(std::move(keiro)); } const auto ans = Board::Merge(keiros); const int hp = board_.Simulate(ans, 0); // TODO:正確に if (hp < board_.H) { return ans; } } assert(false); } private: Board board_; }; int main(int argc, char* argv[]) { fast_io; if (argc >= 2) { // int idx = 0; // for (int i = 1; i < argc; ++i) { // PARAMS[idx++] = std::stod(argv[i]); // } } Timer timer; timer.start(); Solver solver(cin); const auto ans = solver.Solve(2950 - timer.ms()); cout << ans << endl; return 0; }