結果
問題 | No.5006 Hidden Maze |
ユーザー |
|
提出日時 | 2022-06-12 19:01:53 |
言語 | C++17(gcc12) (gcc 12.3.0 + boost 1.87.0) |
結果 |
AC
|
実行時間 | 123 ms / 2,000 ms |
コード長 | 13,172 bytes |
コンパイル時間 | 2,959 ms |
実行使用メモリ | 22,888 KB |
スコア | 86,389 |
平均クエリ数 | 137.11 |
最終ジャッジ日時 | 2022-06-12 19:02:04 |
合計ジャッジ時間 | 10,506 ms |
ジャッジサーバーID (参考情報) |
judge16 / judge11 |
純コード判定しない問題か言語 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 100 |
ソースコード
#pragma GCC optimize ("O3")#pragma GCC optimize ("unroll-loops")#pragma GCC target ("avx2")#include <iostream>#include <iomanip>#include <vector>#include <algorithm>#include <utility>#include <string>#include <queue>#include <stack>#include <unordered_set>#include <random>#include <cmath>#include <cassert>#include <x86intrin.h>struct xorshift64 {unsigned long long int x = 88172645463325252ULL;inline unsigned short nextUShort() {x = x ^ (x << 7);return x = x ^ (x >> 9);}inline unsigned int nextUShortMod(unsigned long long int mod) {x = x ^ (x << 7);x = x ^ (x >> 9);return ((x & 0x0000ffffffffffff) * mod) >> 48;}inline unsigned int nextUInt() {x = x ^ (x << 7);return x = x ^ (x >> 9);}inline unsigned int nextUIntMod(unsigned long long int mod) {x = x ^ (x << 7);x = x ^ (x >> 9);return ((x & 0x00000000ffffffff) * mod) >> 32;}inline unsigned long long int nextULL() {x = x ^ (x << 7);return x = x ^ (x >> 9);}inline double nextDouble() {x = x ^ (x << 7);x = x ^ (x >> 9);return (double)x * 5.42101086242752217e-20;}};struct timer {double t = 0.0;double lastStop = 0.0;bool stopped = false;timer() {restart();}inline void restart() {t = now();stopped = false;}inline void start() {if (stopped) {t += now() - lastStop;stopped = false;}}inline void stop() {if (!stopped) {lastStop = now();stopped = true;}}inline double time() {if (stopped) return lastStop - t;else return now() - t;}inline double now() {unsigned long long l, h;__asm__ ("rdtsc" : "=a"(l), "=d"(h));#ifdef LOCALreturn (double)(l | h << 32) * 2.857142857142857e-10; // 1 / 3.5e9, for local (Ryzen 9 3950X)#else//return (double)(l | h << 32) * 3.5714285714285715e-10; // 1 / 2.8e9, for AWS EC2 C3 (Xeon E5-2680 v2)//return (double)(l | h << 32) * 3.4482758620689656e-10; // 1 / 2.9e9, for AWS EC2 C4 (Xeon E5-2666 v3)return (double)(l | h << 32) * 3.333333333333333e-10; // 1 / 3.0e9, for AWS EC2 C5 (Xeon Platinum 8124M / Xeon Platinum 8275CL)#endif}};using namespace std;typedef long long int ll;typedef unsigned long long int ull;typedef pair<int, int> Pii;const ll mod = 1000000007;timer theTimer;xorshift64 theRandom;mt19937 theMersenne(1);// hyper parameters// structsstruct {const vector<int> x = { -1, 1, 0, 0};const vector<int> y = { 0, 0, -1, 1};const vector<char> c = {'U', 'D', 'L', 'R'};} delta;// constantsconstexpr int h = 20;constexpr int w = 20;constexpr int turn_limit = 1001;constexpr int start_x = 0;constexpr int start_y = 0;constexpr int finish_x = h-1;constexpr int finish_y = w-1;vector<double> edge_cost;// inputsdouble p;// outputsstring ans;// internalsvector<vector<bool> > edge_passable_vertical;vector<vector<bool> > edge_passable_horizontal;vector<vector<int> > edge_wall_hit_count_vertical;vector<vector<int> > edge_wall_hit_count_horizontal;#ifdef LOCAL_TESTvector<vector<bool> > wall_vertical;vector<vector<bool> > wall_horizontal;vector<int> movable_count;#endifbool within_board(int x, int y) {return 0 <= x && x < h && 0 <= y && y < w;}void receive_first_input() {#ifndef LOCAL_TESTint _h, _w, _p;cin >> _h >> _w >> _p;p = (double) _p * 0.01;#elsep = 0.15;unsigned long long int x;cin >> x;theRandom.x = x;// random_device rng;// theRandom.x = ((unsigned long long int) rng() << 32) | (unsigned long long int) rng();#endif}int answer(string ans, int turn_count) {#ifndef LOCAL_TESTcout << ans << endl;#endifint res;#ifndef LOCAL_TESTcin >> res;#elseif (turn_count >= turn_limit - 1) res = -1;else {bool wall_hit = false;int px = start_x;int py = start_y;for (int i = 0; i < (int) ans.size(); i++) {if (i == movable_count[turn_count]) {wall_hit = true;res = i;break;}for (int d = 0; d < 4; d++) {if (delta.c[d] == ans[i]) {if (d & 2) {// horizontal movementassert(delta.x[d] == 0);assert(abs(delta.y[d]) == 1);int wall_y = min(py, py + delta.y[d]);if (wall_horizontal[px + delta.x[d]][wall_y]) {wall_hit = true;res = i;break;}}else {// vertical movementassert(abs(delta.x[d]) == 1);assert(delta.y[d] == 0);int wall_x = min(px, px + delta.x[d]);if (wall_vertical[wall_x][py + delta.y[d]]) {wall_hit = true;res = i;break;}}px += delta.x[d];py += delta.y[d];}}if (wall_hit) break;}if (!wall_hit && px == finish_x && py == finish_y) {res = -1;}else if (!wall_hit) {res = ans.size();}}// cerr << setw(4) << turn_count << " " << setw(4) << res << " " << setw(4) << movable_count[turn_count] << " " << ans << endl;#endifreturn res;}void init() {edge_cost = vector<double>(turn_limit);edge_cost[0] = 1.0;for (int i = 1; i < turn_limit; i++) {edge_cost[i] = edge_cost[i-1] * (1.0 / p);}edge_passable_vertical = vector<vector<bool> >(h-1, vector<bool>(w));edge_passable_horizontal = vector<vector<bool> >(h, vector<bool>(w-1));edge_wall_hit_count_vertical = vector<vector<int> >(h-1, vector<int>(w));edge_wall_hit_count_horizontal = vector<vector<int> >(h, vector<int>(w-1));#ifdef LOCAL_TESTwall_vertical = vector<vector<bool> >(h-1, vector<bool>(w));wall_horizontal = vector<vector<bool> >(h, vector<bool>(w-1));int m = theRandom.nextUIntMod(101) + 100;int wall_created = 0;while (wall_created < m) {int wall_dir = theRandom.nextUIntMod(2);int wall_x, wall_y;if (wall_dir == 0) {wall_x = theRandom.nextUIntMod(h);wall_y = theRandom.nextUIntMod(w-1);if (wall_horizontal[wall_x][wall_y]) continue;wall_horizontal[wall_x][wall_y] = true;}else {wall_x = theRandom.nextUIntMod(h-1);wall_y = theRandom.nextUIntMod(w);if (wall_vertical[wall_x][wall_y]) continue;wall_vertical[wall_x][wall_y] = true;}vector<vector<bool> > visited(h, vector<bool>(w));queue<tuple<int, int> > que;que.emplace(start_x, start_y);while (!que.empty()) {auto [px, py] = que.front();que.pop();if (visited[px][py]) continue;visited[px][py] = true;for (int d = 0; d < 4; d++) {if (within_board(px + delta.x[d], py + delta.y[d]) && !visited[px + delta.x[d]][py + delta.y[d]]) {if (d & 2) {// horizontal movementassert(delta.x[d] == 0);assert(abs(delta.y[d]) == 1);int wall_y = min(py, py + delta.y[d]);if (!wall_horizontal[px + delta.x[d]][wall_y]) {que.emplace(px + delta.x[d], py + delta.y[d]);}}else {// vertical movementassert(abs(delta.x[d]) == 1);assert(delta.y[d] == 0);int wall_x = min(px, px + delta.x[d]);if (!wall_vertical[wall_x][py + delta.y[d]]) {que.emplace(px + delta.x[d], py + delta.y[d]);}}}}}bool all_reachable = true;for (int i = 0; i < h; i++) {for (int j = 0; j < w; j++) {if (!visited[i][j]) {all_reachable = false;break;}}if (!all_reachable) break;}if (all_reachable) wall_created++;else {if (wall_dir == 0) {wall_horizontal[wall_x][wall_y] = false;}else {wall_vertical[wall_x][wall_y] = false;}}}movable_count = vector<int>(turn_limit);for (int i = 0; i < turn_limit; i++) {for (int x = 0; x < 400; x++) {int c = theRandom.nextUIntMod(100);movable_count[i]++;if ((double) c < p * 100.0 - 0.5) break;}}#endif}void solve() {for (int turn_count = 0; turn_count < turn_limit; turn_count++) {// find next pathstring next_path = "";{vector<vector<char> > prev_dir(h, vector<char>(w)); // direction to startvector<vector<bool> > visited(h, vector<bool>(w));priority_queue<tuple<double, int, int, char>, vector<tuple<double, int, int, char> >, greater<tuple<double, int, int, char> > > que;que.emplace(0, start_x, start_y, '.');while (!que.empty()) {auto [current_cost, px, py, dir] = que.top();que.pop();if (visited[px][py]) continue;visited[px][py] = true;prev_dir[px][py] = dir;if (px == finish_x && py == finish_y) break;for (int d = 0; d < 4; d++) {if (within_board(px + delta.x[d], py + delta.y[d]) && !visited[px + delta.x[d]][py + delta.y[d]]) {double penalty = (d & 1 ? edge_cost[1] : 0.0); // penalize U/Lif (d & 2) {// horizontal movementassert(delta.x[d] == 0);assert(abs(delta.y[d]) == 1);int wall_y = min(py, py + delta.y[d]);if (edge_passable_horizontal[px + delta.x[d]][wall_y]) {que.emplace(current_cost + (penalty + theRandom.nextDouble() * 0.001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py +delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip}else {que.emplace(current_cost + (penalty + edge_cost[edge_wall_hit_count_horizontal[px + delta.x[d]][wall_y]] + theRandom.nextDouble() * 0.001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py + delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip}}else {// vertical movementassert(abs(delta.x[d]) == 1);assert(delta.y[d] == 0);int wall_x = min(px, px + delta.x[d]);if (edge_passable_vertical[wall_x][py + delta.y[d]]) {que.emplace(current_cost + (penalty + theRandom.nextDouble() * 0.001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py +delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip}else {que.emplace(current_cost + (penalty + edge_cost[edge_wall_hit_count_vertical[wall_x][py + delta.y[d]]] + theRandom.nextDouble() * 0.001) * (0.9 + theRandom.nextDouble() * 0.1), px + delta.x[d], py + delta.y[d], delta.c[d ^ 1]); // ^ 1: 180 deg flip}}}}}{int px = finish_x;int py = finish_y;while (!(px == start_x && py == start_y)) {assert(within_board(px, py));assert(visited[px][py]);visited[px][py] = false;auto dir = prev_dir[px][py];for (int d = 0; d < 4; d++) {if (delta.c[d] == dir) {next_path.push_back(delta.c[d ^ 1]);px += delta.x[d];py += delta.y[d];break;}}}reverse(next_path.begin(), next_path.end());}}auto res = answer(next_path, turn_count);if (res == -1) {// valid path foundcerr << "Score = " << turn_limit - turn_count - 1 << endl;break;}else {int px = 0;int py = 0;for (int i = 0; i < res; i++) {for (int d = 0; d < 4; d++) {if (delta.c[d] == next_path[i]) {if (d & 2) {// horizontal movementassert(delta.x[d] == 0);assert(abs(delta.y[d]) == 1);int wall_y = min(py, py + delta.y[d]);edge_passable_horizontal[px + delta.x[d]][wall_y] = true;}else {// vertical movementassert(abs(delta.x[d]) == 1);assert(delta.y[d] == 0);int wall_x = min(px, px + delta.x[d]);edge_passable_vertical[wall_x][py + delta.y[d]] = true;}px += delta.x[d];py += delta.y[d];}}}for (int d = 0; d < 4; d++) {if (delta.c[d] == next_path[res]) {if (d & 2) {// horizontal movementassert(delta.x[d] == 0);assert(abs(delta.y[d]) == 1);int wall_y = min(py, py + delta.y[d]);edge_wall_hit_count_horizontal[px + delta.x[d]][wall_y]++;}else {// vertical movementassert(abs(delta.x[d]) == 1);assert(delta.y[d] == 0);int wall_x = min(px, px + delta.x[d]);edge_wall_hit_count_vertical[wall_x][py + delta.y[d]]++;}}}}}}int main(int argc, char *argv[]) {cin.tie(0);ios::sync_with_stdio(false);receive_first_input();init();solve();return 0;}