#include #include #include #include #include #include #include #include #include #include #include #define pb push_back #define mp make_pair using namespace std; const int N = 155; const int MAX_ROBOTS = 22; const int MAX_TESTS = 12; const int SEED = 7129; const double TIME_LIMIT = 4.80; double TIME_PER_TEST; mt19937 mt(SEED); uniform_real_distribution <> rng(0, 1); int range_rng(int l, int r) { return (mt() % (r - l + 1) + l); } int n, m; char tab[N][N]; int t, k; struct point{ int x, y; }; vector r[MAX_TESTS]; char d[4] = {'N', 'E', 'S', 'W'}; int distance(point p, point q) { return abs(p.x - q.x) + abs(p.y - q.y); } point apply_command(point p, char command) { point res = p; if(command == 'N') { res.x--; } if(command == 'E') { res.y++; } if(command == 'S') { res.x++; } if(command == 'W') { res.y--; } if(tab[res.x][res.y] == '#') return p; else return res; } string optimal_sol = "N"; int on_test = 1; /// SIMULATED ANNEALING double T, Tmin, Tmax; double cr; /// cooling ratio int MAX_TRIES; void init_Simulated_Annealing() { Tmin = 0.01; Tmax = 0.30; cr = 1.0 / ((n + m) * (21 - k)); MAX_TRIES = 150; TIME_PER_TEST = TIME_LIMIT / t; } string get_initial_solution(int len) { string res; for(int i = 0; i < len; i++) { res.pb(d[range_rng(0, 3)]); } return res; } int eval(string sol, int test_id) { point fpos[MAX_ROBOTS]; int i, j; for(i = 0; i < k; i++) fpos[i] = r[test_id][i]; for(i = 0; i < k; i++) { for(j = 0; j < sol.size(); j++) { fpos[i] = apply_command(fpos[i], sol[j]); } } int max_dist = 0; for(i = 0; i < k; i++) { for(j = i + 1; j < k; j++) { max_dist = max(max_dist, distance(fpos[i], fpos[j])); } } return sol.size() + max_dist * (n + m); } void simulated_annealing(int test_id) { //for(int tries = 1; tries <= MAX_TRIES; tries++) time_t start = clock(); int iter = 0; while(clock() - start < TIME_PER_TEST * (double)CLOCKS_PER_SEC) { iter++; string sol = get_initial_solution(range_rng(min(n, m), 1 * (n + m))); string best_sol = sol; string candidate_sol; T = Tmax; while(T > Tmin && clock() - start < TIME_PER_TEST * (double)CLOCKS_PER_SEC) { if(eval(sol, test_id) < eval(best_sol, test_id)) { best_sol = sol; } candidate_sol = sol; bool found_new = false; for(int i = 0; i < sol.size() && !found_new; i++) { for(int j = 0; j < 4; j++) { if(d[j] != sol[i]) { candidate_sol[i] = d[j]; int delta = eval(sol, test_id) - eval(candidate_sol, test_id); /// positive if candidate is better if(rng(mt) <= exp(delta / T)) { sol = candidate_sol; found_new = true; break; } } } candidate_sol[i] = sol[i]; } T *= exp(-cr); } if(eval(best_sol, test_id) < eval(optimal_sol, on_test)) { optimal_sol = best_sol; on_test = test_id; } } cerr << iter << endl; } void input() { int i, j; for(i = 0; i < N; i++) for(j = 0; j < N; j++) tab[i][j] = '#'; cin >> n >> m; for(i = 1; i <= n; i++) for(j = 1; j <= m; j++) cin >> tab[i][j]; cin >> t >> k; for(i = 1; i <= t; i++) { point p; for(j = 1; j <= k; j++) { cin >> p.x >> p.y; r[i].pb(p); } } } int main() { ios_base::sync_with_stdio(false); cin.tie(nullptr); cout.tie(nullptr); freopen("robots.in", "r", stdin); freopen("robots.out", "w", stdout); input(); init_Simulated_Annealing(); for(int i = 1; i <= t; i++) { simulated_annealing(i); } cout << on_test << endl; cout << optimal_sol << endl; cerr << eval(optimal_sol, on_test) << endl; return 0; } /* 4 5 .#..# ....# #.#.. ...#. 2 2 1 1 4 5 4 1 4 5 */