Run Time: 0.000
Ranking (as of 2016-08-12): 19 out of 385
Language: C++
/* UVa 10937 - Blackbeard the Pirate To build using Visual Studio 2012: cl -EHsc -O2 UVa_10937_Blackbeard_the_Pirate.cpp This problem is similar to 10944 - Nuts for nuts.. */ #include <algorithm> #include <queue> #include <utility> #include <limits> #include <cstdio> #include <cstring> using namespace std; const int infinite = numeric_limits<int>::max(); const int h_max = 50, w_max = 50, nr_treasures_max = 10; char map[h_max][w_max + 1]; struct place { int r_, c_; place() {} place(int r, int c) : r_(r), c_(c) {} place(const place& p) : r_(p.r_), c_(p.c_) {} } places[nr_treasures_max + 1]; bool visited[h_max][w_max]; int distances[nr_treasures_max + 1][nr_treasures_max + 1]; // distances[i][j] is the distance between the treasures of i and j int bitmasks[1 << (nr_treasures_max + 1)][nr_treasures_max + 1]; const int nr_cardinal_dirs = 4; const pair<int, int> cardinal_dirs[nr_cardinal_dirs] = {make_pair(1, 0), make_pair(0, 1), make_pair(-1, 0), make_pair(0, -1)}; const int nr_diagonal_dirs = 4; const pair<int, int> diagonal_dirs[nr_diagonal_dirs] = {make_pair(1, 1), make_pair(-1, 1), make_pair(-1, -1), make_pair(1, -1)}; int tsp(int nr_treasures, int places, int p) // travelling salesman problem { if (places == (1 << p)) return distances[p][0]; // distance from the landing point to the treasure of p int& d = bitmasks[places][p]; if (d >= 0) return d; d = infinite; for (int i = 0; i < nr_treasures; i++) if (i != p && (places & (1 << i))) d = min(d, distances[p][i] + tsp(nr_treasures, places & ~(1 << p), i)); return d; } int bfs(int h, int w, int s, int nr_treasures) { memset(visited, 0, sizeof(visited)); for (int i = 0; i < nr_treasures; i++) distances[s][i] = infinite; queue< pair<place, int> > q; visited[places[s].r_][places[s].c_] = true; distances[s][s] = 0; q.push(make_pair(places[s], 0)); while (!q.empty()) { place p = q.front().first; int d = q.front().second; q.pop(); for (int i = 0; i < nr_cardinal_dirs; i++) { int nr = p.r_ + cardinal_dirs[i].first, nc = p.c_ + cardinal_dirs[i].second; if (nr >= 0 && nr < h && nc >= 0 && nc < w && map[nr][nc] != -1 && !visited[nr][nc]) { visited[nr][nc] = true; if (map[nr][nc] < nr_treasures) distances[s][map[nr][nc]] = distances[map[nr][nc]][s] = d + 1; q.push(make_pair(place(nr, nc), d + 1)); } } } for (int i = 0; i < nr_treasures; i++) if (distances[s][i] == infinite) return -1; return 0; } int main() { while (true) { int h, w; scanf("%d %d", &h, &w); if (!h) break; int nr_treasures = 1; for (int r = 0; r < h; r++) { scanf("%s", map[r]); for(int c = 0; c < w; c++) switch (map[r][c]) { case '@': places[0].r_ = r, places[0].c_ = c; map[r][c] = 0; break; case '!': places[nr_treasures].r_ = r, places[nr_treasures].c_ = c; map[r][c] = nr_treasures++; break; case '~': case '#': map[r][c] = -1; break; } } int result = 0; for (int r = 0; r < h; r++) for(int c = 0; c < w; c++) if (map[r][c] == '*') { for (int i = 0; i < nr_cardinal_dirs; i++) { int nr = r + cardinal_dirs[i].first, nc = c + cardinal_dirs[i].second; if (nr >= 0 && nr < h && nc >= 0 && nc < w && map[nr][nc] != '*') { if (map[nr][nc] >= 0 && map[nr][nc] < nr_treasures) result = -1; // a treasure is not reachable map[nr][nc] = -1; } if (result == -1) break; } for (int i = 0; i < nr_diagonal_dirs; i++) { int nr = r + diagonal_dirs[i].first, nc = c + diagonal_dirs[i].second; if (nr >= 0 && nr < h && nc >= 0 && nc < w && map[nr][nc] != '*') { if (map[nr][nc] >= 0 && map[nr][nc] < nr_treasures) result = -1; map[nr][nc] = -1; } if (result == -1) break; } if (result == -1) break; } if (result != -1) { // calculate the distances between the treasures/landing point for (int i = 0; i < nr_treasures; i++) if ((result = bfs(h, w, i, nr_treasures)) == -1) break; if (result != -1) { memset(bitmasks, -1, sizeof(bitmasks)); result = tsp(nr_treasures, (1 << nr_treasures) - 1, 0); } } printf("%d\n", result); } return 0; }
No comments:
Post a Comment