#define _CRT_SECURE_NO_WARNINGS #include #include #include #include #include #include #include #include #include #include using namespace std; #define INF 1000000009 const clock_t LIMIT = 4.500 * CLOCKS_PER_SEC; clock_t start; int n, m, t, k; int A[255][255]; bool vis[255][255]; int PAR[255][255]; vector > R[11]; int CORNER_WAY[11]; int DIST_TO_CORNER[11]; int DIST_TO_CORNER_IDX[11]; vector > CR = R[0]; int MOVE[4][2] = { {1,0}, {0,1}, {-1,0}, {0, -1 } }; // calculates the best path for robot at index robotsForSort[0].second // to bestDistWay and push the result in moves void calculateMoves(int robotIdx, int targetRobotIdx, vector& res) { if (robotIdx == targetRobotIdx) return; pair start = CR[robotIdx]; memset(vis, 0, sizeof(vis)); PAR[start.first][start.second] = -1; int tarx = CR[targetRobotIdx].first, tary = CR[targetRobotIdx].second; queue > q; q.push(start); vis[start.first][start.second] = 1; vector MV; while (!q.empty()) { pair tp = q.front(); q.pop(); for (int mm = 0; mm < 4; ++mm) { int nx = tp.first + MOVE[mm][0]; int ny = tp.second + MOVE[mm][1]; if (A[nx][ny] == -1 || vis[nx][ny]) continue; vis[nx][ny] = 1; PAR[nx][ny] = mm; if (nx == tarx && ny == tary) { while (PAR[nx][ny] != -1) { int z = PAR[nx][ny]; MV.push_back(z); if (z == 0) { nx--; } else if (z == 1) { ny--; } else if (z == 2) { nx++; } else if (z == 3) { ny++; } } while (!q.empty()) q.pop(); } else { q.push(make_pair(nx, ny)); } } } for (int j = -1+MV.size(); j >=0; --j) { if (MV[j] == 0) res.push_back('S'); else if (MV[j] == 1) res.push_back('E'); else if (MV[j] == 2) res.push_back('N'); else if (MV[j] == 3) res.push_back('W'); } for (int i = 0; i < k; ++i) { for (int j = -1+MV.size(); j >= 0; --j) { int mv = MV[j]; int nx = CR[i].first + MOVE[mv][0]; int ny = CR[i].second + MOVE[mv][1]; if (A[nx][ny] == -1) { continue; } CR[i].first = nx; CR[i].second = ny; } } } int calculateCurRes(vector& moves) { int res = 0; for (int i = 0; i < k; ++i) { for (int j = 0; j < k; ++j) { if (i == j) continue; res += abs(CR[i].first - CR[j].first); res += abs(CR[i].second- CR[j].second); } } return res*(n+m) + moves.size(); } int main() { start = clock(); //freopen("debug-info.out", "w", stderr); freopen("robots.in", "r", stdin); freopen("robots.out", "w", stdout); memset(A, -1, sizeof(A)); scanf("%d %d\n", &n, &m); char buf[255]; for (int i = 0; i < n; ++i) { scanf("%s\n", buf); for (int j = 0; j < m; ++j) A[1+i][1+j] = (buf[j] == '.') ? 0 : -1; } scanf("%d %d\n", &t, &k); for (int i = 0; i < t; ++i) { CORNER_WAY[i] = -1; DIST_TO_CORNER[i] = INF; DIST_TO_CORNER_IDX[i] = -1; for (int j = 0; j < k; ++j) { int x, y; scanf("%d %d\n", &x, &y); if (x + y < DIST_TO_CORNER[i]) { DIST_TO_CORNER[i] = x-1 + y-1; DIST_TO_CORNER_IDX[i] = j; CORNER_WAY[i] = 0; } if (n - 1 - x + y < DIST_TO_CORNER[i]) { DIST_TO_CORNER[i] = n - x + y-1; DIST_TO_CORNER_IDX[i] = j; CORNER_WAY[i] = 1; } if (n - 1 - x + m - 1 - y < DIST_TO_CORNER[i]) { DIST_TO_CORNER[i] = n - x + m - y; DIST_TO_CORNER_IDX[i] = j; CORNER_WAY[i] = 2; } if (x + m - 1 - y < DIST_TO_CORNER[i]) { DIST_TO_CORNER[i] = x-1 + m - y; DIST_TO_CORNER_IDX[i] = j; CORNER_WAY[i] = 3; } R[i].push_back(make_pair(x, y)); } } // TODO todor91: Don't try to find best test case with heuristic, but // Solve all 10 cases with that solution and get the best result. int BEST_RES = INF; vector BEST_RES_MOVES; vector > BEST_CR; int BEST_RES_TC = -1; for (int THE_WAY = 0; THE_WAY < 29; ++THE_WAY) { if (clock() > LIMIT) break; for (int TEST_CASE = 0; TEST_CASE < t; ++TEST_CASE) { if (clock() > LIMIT) break; CR = R[TEST_CASE]; // first is dist to corenr, second is oroginal robot idx; vector > robotsForSort; for (int i = 0; i < k; ++i) { pair rob = CR[i]; int robDist = 0; if (THE_WAY == 0) { robDist = rob.first - 1 + rob.second - 1; } else if (THE_WAY == 1) { robDist = n - rob.first + rob.second - 1; } else if (THE_WAY == 2) { robDist = n - rob.first + m - rob.second; } else if (THE_WAY == 3) { robDist = rob.first - 1 + m - rob.second; } else if (THE_WAY == 4) { robDist = rob.first - 1; } else if (THE_WAY == 5) { robDist = rob.second - 1; } else if (THE_WAY == 6) { robDist = n - rob.first; } else if (THE_WAY == 7) { robDist = m - rob.second; } else { robDist = 0; } robotsForSort.push_back(make_pair(robDist, i)); } sort(robotsForSort.begin(), robotsForSort.end()); vector moves; if (THE_WAY < 8) { for (int i = 1; i < k; ++i) { // calculates the best path for robot at index robotsForSort[0].second // to bestDistWay and push the result in moves calculateMoves(robotsForSort[i].second, robotsForSort[0].second, moves); } } else { int targetRobot = rand() % k; for (int i = 0; i < k; ++i) { // calculates the best path for robot at index robotsForSort[0].second // to bestDistWay and push the result in moves calculateMoves(robotsForSort[i].second, targetRobot, moves); } } // Calculate diff and redo prev step // TODO REFINE THIS 10!!! for (int i = 0; i < 5; ++i) { int best1 = INF; int best1i = -1; for (int i = 0; i < k; ++i) { int cur = 0; for (int j = 0; j < k; ++j) { cur += abs(CR[i].first - CR[j].first); cur += abs(CR[i].second - CR[j].second); } if (cur < best1) { best1 = cur; best1i = i; } } if (best1 > 0 && best1 < INF) { for (int i = 0; i < k; ++i) { if (i == best1i) continue; calculateMoves(i, best1i, moves); } } } int curRes = calculateCurRes(moves); if (curRes < BEST_RES) { //fprintf(stderr, "%d, time: %d\n", curRes, clock()); BEST_RES = curRes; BEST_RES_MOVES = moves; BEST_RES_TC = TEST_CASE; BEST_CR = CR; } } } // Calculate the closest robot to every other robot. // And move all robots to the closest one. printf("%d\n", BEST_RES_TC + 1); if (BEST_RES_MOVES.size() == 0) { putchar('N'); } else { int MAX_MOVES = min(100000, (int)BEST_RES_MOVES.size()); for (int i = 0; i < MAX_MOVES; ++i) { putchar(BEST_RES_MOVES[i]); } } printf("\n"); return 0; }