// pinball.cpp : Defines the entry point for the console application. // #include #include #include #include #include #include #include #include #include #include using namespace std; class msg_exception : exception { const string _msg; public: msg_exception(const string& msg) : _msg(msg) {} ~msg_exception() throw() {} virtual const char* what() const throw() { return _msg.c_str(); } }; struct coord { int x, y; coord(int x_, int y_) : x(x_), y(y_) {} }; struct turn_info { // coordinate of the flip coord xy; // true if added by solution bool added; // true if flipped by solution bool flipped; turn_info(int x_, int y_, bool added_) : xy(x_, y_), added(added_) { } }; #if _DEBUG inline bool not_expired1() { return true; } inline bool not_expired() { return true; } #else chrono::steady_clock::time_point end1_time = chrono::steady_clock::now() + chrono::milliseconds(3000); inline bool not_expired1() { return chrono::steady_clock::now() < end1_time; } chrono::steady_clock::time_point end_time = chrono::steady_clock::now() + chrono::milliseconds(4850); inline bool not_expired() { return chrono::steady_clock::now() < end_time; } #endif struct info { int N, M, A, C; vector pts; vector map; list turns; int total_pts; info(const char* fin_name) { ifstream fin(fin_name); fin >> N >> M; if (N < 1 || N > 400) throw msg_exception("Invalid N"); if (M < 1 || M > 400) throw msg_exception("Invalid M"); fin >> A >> C; if (A < 0 || A > 20000) throw msg_exception("Invalid A"); if (C < 0 || C > 20000) throw msg_exception("Invalid C"); // resize map pts.resize(N * M, 0); map.resize(N * M, 0); total_pts = 0; // read map for (int y = 0; y < N; y++) { char ch; for (int x = 0; x < M; x++) { fin >> ch; if (ch == '/') { set_map(map, x, y, 2); turns.push_back(turn_info(x, y, false)); } else if (ch == '\\') { set_map(map, x, y, 1); turns.push_back(turn_info(x, y, false)); } else if (ch == '.') { set_map(map, x, y, 0); } else throw msg_exception("Invalid map"); } } // read points for (int y = 0; y < N; y++) { int pts; for (int x = 0; x < M; x++) { fin >> pts; if (pts < 0 || pts > 1000) throw msg_exception("Invalid map"); total_pts += pts; set_pts(x, y, pts); } } fin.close(); } inline char get_map(const vector& map, int x, int y) const { return map[index(x, y)]; } inline void set_map(vector& map, int x, int y, char value) const { map[index(x, y)] = value; } inline short get_pts(int x, int y) const { return pts[index(x, y)]; } inline void set_pts(int x, int y, short value) { pts[index(x, y)] = value; } inline int index(int x, int y) const { return x + (y * M); } inline int index(const coord& c) const { return index(c.x, c.y); } }; struct solution : info { vector> passes; int best_row; solution(const info& in) : info(in) { passes.resize(in.N * in.M); } void write(const char* fout_name) const { ofstream fout(fout_name); // write row fout << best_row + 1 << endl; // write map for (int y = 0; y < N; y++) { for (int x = 0; x < M; x++) { char ch = get_map(map, x, y); if (ch == 2) fout << '/'; else if(ch == 1) fout << '\\'; else if(ch == 0) fout << '.'; else throw msg_exception("Invalid remap"); } fout << endl; } fout.close(); } int get_score(int r, bool update_passes) { int score = 0; vector map2(map); int dx = 1, dy = 0, x = 0, y = r, n = N, m = M; while (x >= 0 && x < m && y >= 0 && y < n) { if (update_passes) passes[index(x, y)].insert(r); score += get_pts(x, y); char ch = get_map(map2, x, y); if (ch == 2) // / { set_map(map2, x, y, 0); if (dx == 0) { dx = -dy, dy = 0; } else { dy = -dx, dx = 0; } } else if (ch == 1) // { set_map(map2, x, y, 0); if (dx == 0) { dx = dy, dy = 0; } else { dy = dx, dx = 0; } } x += dx; y += dy; } return score; } int find_best_row() { int rm = 0, sm = 0, n = N; for(int y = 0; y < n && not_expired(); y++) { int sy = get_score(y, true); #if _DEBUG cout << "y = " << y << ", s = " << sy << endl; #endif if (sm < sy) { sm = sy; rm = y; } } best_row = rm; return sm; } int check_rows(const set& rows) { int rm = 0, sm = 0; for(set::const_iterator i(rows.begin()), e(rows.end()); i != e; i++) { int y = *i; int sy = get_score(y, false); #if _DEBUG cout << "y = " << y << ", s = " << sy << endl; #endif if (sm < sy) { sm = sy; rm = y; } } best_row = rm; return sm; } void solve() { solveSwapTurns(); solveNoPenalty(); } void solveNoPenalty() { int score = 0, best_score = find_best_row(); vector moves; moves.reserve(N * M); vector map2(map), best_map(map); int dx = 1, dy = 0, x = 0, y = best_row, n = N, m = M; bool forward = true; while (not_expired()) { if (forward) { score += get_pts(x, y); char ch = get_map(map2, x, y); moves.push_back(ch); if ((ch&0x82) == 2) // / { if (dx == 0) { dx = -dy, dy = 0; } else { dy = -dx, dx = 0; } } else if ((ch&0x81) == 1) // { if (dx == 0) { dx = dy, dy = 0; } else { dy = dx, dx = 0; } } set_map(map2, x, y, 0x80 | ch); x += dx; y += dy; if (x < 0 || x >= m || y < 0 || y >= n) { if (best_score < score) { best_score = score; best_map = map2; } forward = false; } } else { if (moves.empty()) break; x -= dx; y -= dy; score -= get_pts(x, y); char ch = moves.back(); moves.pop_back(); if ((ch&0x82) == 2) // / { if (dx == 0) { dx = -dy, dy = 0; } else { dy = -dx, dx = 0; } } else if ((ch&0x81) == 1) // { if (dx == 0) { dx = dy, dy = 0; } else { dy = dx, dx = 0; } } if (ch == 2) { set_map(map2, x, y, 0x21); score -= C; forward = true; } else if (ch == 0x21) { score += C; set_map(map2, x, y, 2); } else if (ch == 1) // { set_map(map2, x, y, 0x22); score -= C; forward = true; } else if (ch == 0x22) // { score += C; set_map(map2, x, y, 1); } else if (ch == 0) { set_map(map2, x, y, 0x11); score -= A; forward = true; } else if (ch == 0x11) { set_map(map2, x, y, 0x12); forward = true; } else if (ch == 0x12) { score += A; set_map(map2, x, y, 0x10); } } } if (best_score < score) { best_score = score; best_map = map2; } map = best_map; // clear any upper bit flags for (int i = 0, c = N * M; i < c; i++) map[i] &= 3; } void solveSwapTurns() { int sm = 0, bestR = best_row; // total penalty points int penalty = 0; sm = find_best_row(); bestR = best_row; if (!turns.empty()) { bool changed = false; do { for(list::iterator i(turns.begin()), e(turns.end()); i != e && not_expired(); i++) { const coord& xy = i->xy; switch_dir(xy); int dpenalty = (i->added ? 0 : i->flipped ? -C : C); int sm2 = check_rows(passes[index(xy)]) - penalty - dpenalty; if (sm < sm2) { sm = sm2; bestR = best_row; penalty += dpenalty; i->flipped = !i->flipped; changed = true; } else { switch_dir(xy); } } } while(changed && not_expired1()); } best_row = bestR; } void switch_dir(const coord& c) { int x = c.x, y = c.y; if (x < 0 || y < 0) return; char d = get_map(map, x, y); if (d == 2) set_map(map, x, y, 1); else if(d == 1) set_map(map, x, y, 2); } }; void generate(const char* fn, int minN, int maxN, int minM, int maxM, int minA, int maxA, int minC, int maxC, int minP, int maxP, int turns) { int N = minN + rand() % (maxN - minN + 1), M = minM + rand() % (maxM - minM + 1); int A = minA + rand() % (maxA - minA + 1), C = minC + rand() % (maxC - minC + 1); ofstream ofs(fn); ofs << N << " " << M << endl; ofs << A << " " << C << endl; for(int i = 0; i < N; i++) { for (int x = 0; x < M; x++) { int r = turns == 0 ? 2 : rand() % (N * M / turns); char c = r == 0 ? '\\' : r == 1 ? '/' : '.'; ofs << c; } ofs << endl; } for(int i = 0; i < N; i++) { for (int x = 0; x < M; x++) { int P = minP + rand() % (maxP - minP + 1); ofs << P << " "; } ofs << endl; } ofs.close(); } int main(int argc, char* argv[]) { try { //generate("pinball2.in", 50, 50, 50, 50, 0, 0, 10, 10, 10, 10, 8); //generate("pinball2.in", 400, 400, 400, 400, 0, 0, 100, 100, 10, 100, 1024); info i("pinball.in"); solution s(i); s.solve(); s.write("pinball.out"); return 0; } catch(exception ex) { cerr << ex.what() << endl; return 1; } }