結果
問題 | No.5015 Escape from Labyrinth |
ユーザー | tabae326 |
提出日時 | 2023-04-15 20:33:17 |
言語 | C++17 (gcc 12.3.0 + boost 1.83.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 15,007 bytes |
コンパイル時間 | 6,868 ms |
コンパイル使用メモリ | 300,572 KB |
実行使用メモリ | 4,376 KB |
スコア | 78,910 |
最終ジャッジ日時 | 2023-04-15 20:38:04 |
合計ジャッジ時間 | 286,092 ms |
ジャッジサーバーID (参考情報) |
judge11 / judge15 |
(要ログイン)
テストケース
テストケース表示入力 | 結果 | 実行時間 実行使用メモリ |
---|---|---|
testcase_00 | AC | 2,708 ms
4,368 KB |
testcase_01 | AC | 2,707 ms
4,368 KB |
testcase_02 | AC | 2,709 ms
4,368 KB |
testcase_03 | AC | 2,709 ms
4,368 KB |
testcase_04 | AC | 2,709 ms
4,372 KB |
testcase_05 | AC | 2,709 ms
4,368 KB |
testcase_06 | AC | 2,710 ms
4,368 KB |
testcase_07 | AC | 2,709 ms
4,372 KB |
testcase_08 | AC | 2,709 ms
4,372 KB |
testcase_09 | WA | - |
testcase_10 | AC | 2,710 ms
4,372 KB |
testcase_11 | AC | 2,709 ms
4,372 KB |
testcase_12 | AC | 2,710 ms
4,368 KB |
testcase_13 | WA | - |
testcase_14 | WA | - |
testcase_15 | AC | 2,710 ms
4,372 KB |
testcase_16 | AC | 2,709 ms
4,372 KB |
testcase_17 | AC | 2,710 ms
4,368 KB |
testcase_18 | AC | 2,710 ms
4,372 KB |
testcase_19 | AC | 2,709 ms
4,372 KB |
testcase_20 | AC | 2,710 ms
4,368 KB |
testcase_21 | AC | 2,710 ms
4,372 KB |
testcase_22 | AC | 2,709 ms
4,372 KB |
testcase_23 | AC | 2,710 ms
4,368 KB |
testcase_24 | AC | 2,710 ms
4,368 KB |
testcase_25 | AC | 2,709 ms
4,368 KB |
testcase_26 | AC | 2,710 ms
4,368 KB |
testcase_27 | AC | 2,710 ms
4,372 KB |
testcase_28 | AC | 2,709 ms
4,368 KB |
testcase_29 | AC | 2,710 ms
4,372 KB |
testcase_30 | AC | 2,710 ms
4,368 KB |
testcase_31 | AC | 2,709 ms
4,372 KB |
testcase_32 | AC | 2,709 ms
4,368 KB |
testcase_33 | AC | 2,709 ms
4,372 KB |
testcase_34 | WA | - |
testcase_35 | AC | 2,711 ms
4,372 KB |
testcase_36 | AC | 2,710 ms
4,368 KB |
testcase_37 | AC | 2,710 ms
4,372 KB |
testcase_38 | AC | 2,710 ms
4,368 KB |
testcase_39 | AC | 2,709 ms
4,368 KB |
testcase_40 | AC | 2,709 ms
4,368 KB |
testcase_41 | AC | 2,710 ms
4,368 KB |
testcase_42 | AC | 2,709 ms
4,368 KB |
testcase_43 | AC | 2,707 ms
4,372 KB |
testcase_44 | WA | - |
testcase_45 | AC | 2,710 ms
4,372 KB |
testcase_46 | AC | 2,710 ms
4,372 KB |
testcase_47 | AC | 2,710 ms
4,372 KB |
testcase_48 | AC | 2,709 ms
4,368 KB |
testcase_49 | WA | - |
testcase_50 | AC | 2,709 ms
4,368 KB |
testcase_51 | AC | 2,708 ms
4,372 KB |
testcase_52 | AC | 2,710 ms
4,368 KB |
testcase_53 | AC | 2,710 ms
4,372 KB |
testcase_54 | WA | - |
testcase_55 | AC | 2,710 ms
4,368 KB |
testcase_56 | AC | 2,710 ms
4,372 KB |
testcase_57 | AC | 2,709 ms
4,368 KB |
testcase_58 | AC | 2,710 ms
4,372 KB |
testcase_59 | AC | 2,708 ms
4,368 KB |
testcase_60 | AC | 2,709 ms
4,376 KB |
testcase_61 | AC | 2,710 ms
4,368 KB |
testcase_62 | AC | 2,710 ms
4,368 KB |
testcase_63 | AC | 2,709 ms
4,368 KB |
testcase_64 | AC | 2,710 ms
4,372 KB |
testcase_65 | AC | 2,709 ms
4,368 KB |
testcase_66 | AC | 2,709 ms
4,368 KB |
testcase_67 | AC | 2,709 ms
4,368 KB |
testcase_68 | AC | 2,709 ms
4,372 KB |
testcase_69 | AC | 2,711 ms
4,372 KB |
testcase_70 | AC | 2,709 ms
4,372 KB |
testcase_71 | AC | 2,709 ms
4,368 KB |
testcase_72 | AC | 2,710 ms
4,368 KB |
testcase_73 | AC | 2,709 ms
4,368 KB |
testcase_74 | AC | 2,709 ms
4,368 KB |
testcase_75 | AC | 2,708 ms
4,368 KB |
testcase_76 | AC | 2,710 ms
4,368 KB |
testcase_77 | AC | 2,709 ms
4,372 KB |
testcase_78 | AC | 2,710 ms
4,372 KB |
testcase_79 | AC | 2,709 ms
4,368 KB |
testcase_80 | AC | 2,708 ms
4,372 KB |
testcase_81 | AC | 2,708 ms
4,368 KB |
testcase_82 | AC | 2,709 ms
4,372 KB |
testcase_83 | AC | 2,708 ms
4,368 KB |
testcase_84 | AC | 2,710 ms
4,368 KB |
testcase_85 | AC | 2,711 ms
4,368 KB |
testcase_86 | AC | 2,709 ms
4,368 KB |
testcase_87 | AC | 2,709 ms
4,368 KB |
testcase_88 | AC | 2,710 ms
4,372 KB |
testcase_89 | AC | 2,710 ms
4,372 KB |
testcase_90 | AC | 2,710 ms
4,372 KB |
testcase_91 | AC | 2,710 ms
4,368 KB |
testcase_92 | AC | 2,709 ms
4,368 KB |
testcase_93 | AC | 2,710 ms
4,372 KB |
testcase_94 | AC | 2,710 ms
4,372 KB |
testcase_95 | AC | 2,710 ms
4,368 KB |
testcase_96 | AC | 2,709 ms
4,372 KB |
testcase_97 | AC | 2,709 ms
4,368 KB |
testcase_98 | AC | 2,710 ms
4,372 KB |
testcase_99 | AC | 2,711 ms
4,368 KB |
ソースコード
#include <bits/stdc++.h> #include <sys/time.h> #include <atcoder/all> using namespace std; #define n_kinds 26 /*乱数生成器*/ struct RandGenerator { random_device seed_gen; mt19937 engine; mt19937_64 engine64; static const int pshift = 1000000000; RandGenerator() : engine(seed_gen()), engine64(seed_gen()) {} /*mod以下の乱数を返す(32bit)*/ int rand(int mod) { return engine() % mod; } /*mod以下の乱数を返す(64bit)*/ long long randll(long long mod) { return engine64() % mod; } /*確率pでTrueを返す*/ bool pjudge(double p) { int p_int; if(p > 1) p_int = pshift; else p_int = p * pshift; return rand(pshift) < p_int; } } ryuka; /*タイマー*/ struct Timer { double global_start; /*現在の時刻を返す*/ double gettime() { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec + tv.tv_usec * 1e-6; } void init() { global_start = gettime(); } /*プログラム開始からの経過時間を返す*/ double elapsed() { return gettime() - global_start; } } toki; struct Input { int n, d, h; vector<string> s; int m; vector<tuple<int,int,int>> sensors; pair<int,int> start_pos, goal_pos, key_pos; vector<vector<bool>> reachable; vector<vector<map<pair<int,int>,int>>> dist; vector<vector<int>> d_mod; void read() { cin >> n >> d >> h; s.resize(n); for(int i = 0; i < n; i++) cin >> s[i]; cin >> m; sensors.resize(m); d_mod.resize(n, vector<int>(n, 1<<30)); for(auto& [i, j, d] : sensors) { cin >> i >> j >> d; d_mod[i][j] = d; } for(int i = 0; i < n; i++) { for(int j = 0; j < n; j++) { if(s[i][j] == 'S') start_pos = {i, j}; if(s[i][j] == 'G') goal_pos = {i, j}; if(s[i][j] == 'K') key_pos = {i, j}; } } reachable.resize(n, vector<bool>(n, false)); queue<pair<int,int>> que; que.push(start_pos); reachable[start_pos.first][start_pos.second] = true; const int di[] = {-1, 1, 0, 0}; const int dj[] = {0, 0, -1, 1}; while(!que.empty()) { auto [ci, cj] = que.front(); que.pop(); for(int k = 0; k < 4; k++) { int ni = ci + di[k]; int nj = cj + dj[k]; if(ni >= 0 && nj >= 0 && ni < n && nj < n && !reachable[ni][nj] && s[ni][nj] != '#' && s[ni][nj] != 'E' && s[ni][nj] != 'G') { que.push({ni, nj}); reachable[ni][nj] = true; } } } } } input; enum struct Command { Stay, Move, Build, Fire }; struct Operation { Command cmd; int dir; void print(); Operation() {} Operation(Command cmd) : cmd(cmd) {} Operation(Command cmd, int dir) : cmd(cmd), dir(dir) {} }; struct Output { vector<Operation> ans; void print() { for(Operation& e: ans) e.print(); } }; struct State { long long score; vector<pair<int,int>> path; State() : score(1LL<<60) {} static State initState(); static State generateState(const State& input_state); }; /*イテレーション管理クラス*/ template<class STATE> struct IterationControl { int iteration_counter; int swap_counter; double average_time; double start_time; IterationControl() : iteration_counter(0), swap_counter(0) {} /*山登り法*/ STATE climb(double time_limit, STATE initial_state) { start_time = toki.gettime(); average_time = 0; STATE best_state = initial_state; double time_stamp = start_time; cerr << "[INFO] - IterationControl::climb - Starts climbing...\n"; while(time_stamp - start_time + average_time < time_limit) { STATE current_state = STATE::generateState(best_state); if(current_state.score < best_state.score) { swap(best_state, current_state); swap_counter++; } iteration_counter++; time_stamp = toki.gettime(); average_time = (time_stamp - start_time) / iteration_counter; } cerr << "[INFO] - IterationControl::climb - Iterated " << iteration_counter << " times and swapped " << swap_counter << " times.\n"; return best_state; } /*焼きなまし法*/ STATE anneal(double time_limit, double temp_start, double temp_end, STATE initial_state) { start_time = toki.gettime(); average_time = 0; STATE best_state = initial_state; double elapsed_time = 0; cerr << "[INFO] - IterationControl::anneal - Starts annealing...\n"; while(elapsed_time + average_time < time_limit) { double normalized_time = elapsed_time / time_limit; double temp_current = pow(temp_start, 1.0 - normalized_time) * pow(temp_end, normalized_time); STATE current_state = STATE::generateState(best_state); long long delta = current_state.score - best_state.score; if(delta > 0 || ryuka.pjudge(exp(1.0 * delta / temp_current)) ) { swap(best_state, current_state); swap_counter++; } iteration_counter++; elapsed_time = toki.gettime() - start_time; average_time = elapsed_time / iteration_counter; } cerr << "[INFO] - IterationControl::anneal - Iterated " << iteration_counter << " times and swapped " << swap_counter << " times.\n"; return best_state; } }; namespace Utils { const int di[] = {-1, 1, 0, 0}; const int dj[] = {0, 0, -1, 1}; pair<int, int> dir_to_delta(int dir) { return {di[dir], dj[dir]}; } pair<int, int> dir_to_pos(int i, int j, int dir) { return {i + di[dir], j + dj[dir]}; } char dir_to_UDLR(int dir) { return "UDLR"[dir]; } int calc_dist(pair<int,int> a, pair<int,int> b) { return abs(a.first - b.first) + abs(a.second - b.second); } vector<pair<int,int>> generatePathNN() { pair<int,int> current_pos = input.start_pos; bool got_key = false; vector seen(input.n, vector<bool>(input.n, false)); vector<pair<int,int>> path; seen[current_pos.first][current_pos.second] = true; while(true) { auto [ci, cj] = current_pos; path.push_back(current_pos); int min_dist = 1<<30; pair<int, int> nearest_pos; for(int search_range = 5; search_range <= 30; search_range += 5) { for(int i = max(0, ci - search_range); i < min(input.n, ci + search_range); i++) { for(int j = max(0, cj - search_range); j < min(input.n, cj + search_range); j++) { if(input.reachable[i][j] && !seen[i][j] && (input.s[i][j] == 'J' || /*input.s[i][j] == 'F' ||*/ input.s[i][j] == 'K')) { // TODO: 厳密な距離に置き換える? よくよく考えると、宝石や火薬は30%くらいしか無いから、1000^2くらいに収まる // 経路も記録しておけるか? 火薬は拾いに行く? int current_dist = abs(i - ci) + abs(j - cj); if(min_dist > current_dist) { min_dist = current_dist; nearest_pos = {i, j}; } } } } if(min_dist != (1<<30)) { current_pos = nearest_pos; seen[nearest_pos.first][nearest_pos.second] = true; if(input.s[nearest_pos.first][nearest_pos.second] == 'K') got_key = true; break; } } if(min_dist == (1<<30)) { if(!got_key) path.push_back(input.key_pos); path.push_back(input.goal_pos); break; } } return path; } vector<pair<int,int>> searchPath(pair<int,int> start, pair<int,int> goal, bool goal_ok) { queue<pair<int,int>> que; vector seen(input.n, vector<bool>(input.n, false)); vector from(input.n, vector<pair<int,int>>(input.n)); que.push(start); seen[start.first][start.second] = true; while(!que.empty()) { auto [ci, cj] = que.front(); que.pop(); for(int dir = 0; dir < 4; dir++) { int ni = ci + Utils::di[dir]; int nj = cj + Utils::dj[dir]; if(ni >= 0 && nj >= 0 && ni < input.n && nj < input.n && !seen[ni][nj] && input.s[ni][nj] != '#' && input.s[ni][nj] != 'E' && !(!goal_ok && input.s[ni][nj] == 'G')) { que.push({ni, nj}); seen[ni][nj] = true; from[ni][nj] = {ci, cj}; } } if(seen[goal.first][goal.second]) break; } if(!seen[goal.first][goal.second]) { cerr << "Error! (" << start.first << "," << start.second << ") -> "; cerr << "(" << goal.first << "," << goal.second << ") is impossible!\n"; for(auto e : input.s) cerr << e << endl; exit(1); } vector<pair<int,int>> path; pair<int,int> current_pos = goal; path.push_back(current_pos); while(current_pos != start) { current_pos = from[current_pos.first][current_pos.second]; path.push_back(current_pos); } reverse(path.begin(), path.end()); return path; } Output convertPathToOperations(const vector<pair<int,int>>& path) { Output res; for(int i = 0; i < path.size()-1; i++) { auto local_path = searchPath(path[i], path[i+1], i == path.size()-2); for(int j = 0; j < local_path.size()-1; j++) { pair<int, int> delta = {local_path[j+1].first - local_path[j].first, local_path[j+1].second - local_path[j].second}; for(int dir = 0; dir < 4; dir++) { if(dir_to_delta(dir) == delta) { res.ans.push_back(Operation(Command::Move, dir)); break; } } } } return res; } long long calcScore(const State& state) { long long res = 0; return res; } Output saveLife(Output raw_output) { cerr << "Starts saveLife..." << endl; int hp = input.h; int turn = 1; auto [ci, cj] = input.start_pos; bool got_key = false; bool got_goal = false; Output res; for(Operation op: raw_output.ans) { if(input.key_pos == make_pair(ci, cj)) { got_key = true; } if(input.goal_pos == make_pair(ci, cj)) { got_goal = true; break; } if(got_key) { if(hp < 300) break; } else { if(hp < 600) break; } res.ans.push_back(op); if(op.cmd == Command::Move) { ci += Utils::di[op.dir]; cj += Utils::dj[op.dir]; for(int dir = 0; dir < 4; dir++) { int ni = ci + Utils::di[dir]; int nj = cj + Utils::dj[dir]; while(ni >= 0 && nj >= 0 && ni < input.n && nj < input.n) { if(input.s[ni][nj] == '#') { break; } else if(input.s[ni][nj] == 'E') { if(turn % input.d_mod[ni][nj] == 0) { hp -= input.d; } break; } ni += Utils::di[dir]; nj += Utils::dj[dir]; } } } else { assert(false); } turn++; hp--; } if(!got_goal) { vector<pair<int,int>> path; if(!got_key) { path.push_back({ci, cj}); ci = input.key_pos.first; cj = input.key_pos.second; } path.push_back({ci, cj}); path.push_back(input.goal_pos); auto ops_to_goal = Utils::convertPathToOperations(path); for(auto e : ops_to_goal.ans) res.ans.push_back(e); } return res; } } void Operation::print() { if(cmd == Command::Stay) { cout << "S\n"; } else if(cmd == Command::Move) { cout << "M " << Utils::dir_to_UDLR(dir) << "\n"; } else if(cmd == Command::Build) { cout << "B " << Utils::dir_to_UDLR(dir) << "\n"; } else if(cmd == Command::Fire) { cout << "F " << Utils::dir_to_UDLR(dir) << "\n"; } } State State::initState() { State res; res.path = Utils::generatePathNN(); res.score = 0; for(int i = 0; i < res.path.size()-1; i++) { res.score += Utils::calc_dist(res.path[i], res.path[i+1]); } return res; } State State::generateState(const State &input_state) { State res = input_state; int i = ryuka.rand(res.path.size()-2)+1; int j = ryuka.rand(res.path.size()-2)+1; if(i != j) { res.score -= Utils::calc_dist(res.path[i-1], res.path[i]); res.score -= Utils::calc_dist(res.path[i], res.path[i+1]); res.score -= Utils::calc_dist(res.path[j-1], res.path[j]); res.score -= Utils::calc_dist(res.path[j], res.path[j+1]); swap(res.path[i], res.path[j]); res.score += Utils::calc_dist(res.path[i-1], res.path[i]); res.score += Utils::calc_dist(res.path[i], res.path[i+1]); res.score += Utils::calc_dist(res.path[j-1], res.path[j]); res.score += Utils::calc_dist(res.path[j], res.path[j+1]); } return res; } int main(int argc, char* argv[]) { toki.init(); input.read(); double temp_start = 95341.24848473762; double temp_end = 3.281132005830301; #ifdef OPTUNA if(argc == 3) { temp_start = atof(argv[1]); temp_end = atof(argv[2]); cerr << "[INFO] - main - temp_start is " << temp_start << "\n"; cerr << "[INFO] - main - temp_end is " << temp_end << "\n"; } #endif IterationControl<State> sera; // annealに変更するときは最小値を探していることに気を付ける // State res = sera.climb(10, State::initState()); State res = sera.climb(2.7, State::initState()); Output ans = Utils::convertPathToOperations(res.path); ans = Utils::saveLife(ans); ans.print(); }