【UVa10606】Mines For Diamonds 题解(bfs+枚举)
新博客:debug18.com 使用hexo搭建,欢迎来踩~
传送门:https://uva.onlinejudge.org/external/106/10605.pdf
题目大意:给你一个N * M的矩阵,一些格子中分布着钻石(地雷),需要找到若干条不分岔的从边界开始延伸的道路,可以覆盖所有的钻石。求这些道路覆盖的最小方格数。下图中的答案为11。
看到题首先想到用bfs预处理出每对钻石之间的距离以及每个钻石到边界的最短距离,这个可以由对每个钻石bfs求出。
接下来枚举钻石的排列,枚举出来排列之后就可以贪心扫一遍了。具体来说,依次考虑每个钻石,对于一个钻石既可以选择连向后一个,也可以选择不连成为这条链的终点,然后下一个钻石再向墙连边。这两种决策贪心取最小即可。时间复杂度O(N!*N),可以接受。
(其实这个算法有个漏洞:无法防止路径交叉的情况出现。然而我并不能证明路径交叉的情况一定不是最小值,只能脑补一下了……)
这样的话貌似建个图跑个最短路也能过……吗?
请勿吐槽变量名……
代码(299msAC):
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cstring> 4 #include <cmath> 5 #include <cctype> 6 #include <cassert> 7 #include <ctime> 8 #include <algorithm> 9 #include <utility> 10 #include <functional> 11 12 #define X first 13 #define Y second 14 #define MP make_pair 15 #define BP push_back 16 #define SZ(x) ((int)(x).size()) 17 #define ALL(x) (x).begin(), (x).end() 18 #define DEBUG(...) fprintf(stderr, __VA_ARGS__) 19 20 using namespace std; 21 22 typedef long long LL; 23 typedef pair<int, int> Pii; 24 25 const int oo = 0x3f3f3f3f; 26 27 template<class T> T read(T &x) 28 { 29 T f = 1; 30 char ch = getchar(); 31 while (!isdigit(ch)) { 32 if (ch == '-') 33 f = -1; 34 ch = getchar(); 35 } 36 for (x = 0; isdigit(ch); ch = getchar()) 37 x = 10 * x + ch - '0'; 38 39 return x *= f; 40 } 41 42 const int MAXN = 15, FUCKER_SIZE = 15; 43 const int dx[] = {-1, 0, 1, 0}, dy[] = {0, -1, 0, 1}; 44 45 int N, M; 46 int A[MAXN][MAXN]; 47 int totFucker; 48 Pii fucker[FUCKER_SIZE]; 49 50 int dist[FUCKER_SIZE][FUCKER_SIZE]; 51 52 void bfs(int s) 53 { 54 static int dis[MAXN][MAXN]; 55 static Pii q[MAXN*MAXN]; 56 int front = 0, rear = 0; 57 memset(dis, 0, sizeof(dis)); 58 q[rear++] = fucker[s]; 59 dis[fucker[s].X][fucker[s].Y] = 1; 60 while (front != rear) { 61 Pii u = q[front++]; 62 for (int i = 0; i < 4; i++) { 63 Pii v(u.X + dx[i], u.Y + dy[i]); 64 if (v.X == 0 || v.Y == 0 || v.X > N || v.Y > M || dis[v.X][v.Y]) 65 continue; 66 67 dis[v.X][v.Y] = dis[u.X][u.Y] + 1; 68 if (A[v.X][v.Y] == 0) { 69 if (dist[s][0] == 0) 70 dist[s][0] = dis[v.X][v.Y] - 1; 71 } else { 72 q[rear++] = v; 73 if (A[v.X][v.Y] > 1) 74 dist[s][A[v.X][v.Y]-1] = dis[v.X][v.Y] - 1; 75 } 76 } 77 } 78 } 79 80 int main() 81 { 82 #ifndef ONLINE_JUDGE 83 freopen("tmp.in" ,"r", stdin); 84 freopen("tmp.out", "w", stdout); 85 #endif // ONLINE_JUDGE 86 int T; 87 read(T); 88 while (T--) { 89 read(N); read(M); 90 totFucker = 0; 91 for (int i = 1; i <= N; i++) { 92 static char inp[MAXN]; 93 scanf("%s", inp); 94 for (int j = 1; j <= M; j++) { 95 if (inp[j-1] == '#') 96 A[i][j] = 0; 97 else if (inp[j-1] == '.') 98 A[i][j] = 1; 99 else { 100 A[i][j] = 1 + (++totFucker); 101 fucker[totFucker] = MP(i, j); 102 } 103 } 104 } 105 106 for (int i = 1; i <= totFucker; i++) { 107 memset(dist[i], 0, sizeof(dist[i])); 108 bfs(i); 109 } 110 111 static int p[FUCKER_SIZE]; 112 int ans = 0; 113 for (int i = 1; i <= totFucker; i++) { 114 ans += dist[i][0]; 115 p[i] = i; 116 } 117 do { 118 int res = dist[p[1]][0]; 119 for (int i = 1; i < totFucker; i++) { 120 res += min(dist[p[i]][p[i+1]], dist[p[i+1]][0]); 121 if (res + totFucker - i - 1 > ans) { 122 res = oo; 123 break; 124 } 125 } 126 ans = min(ans, res); 127 } while (next_permutation(p + 1, p + 1 + totFucker)); 128 129 printf("%d\n", ans); 130 131 } 132 133 return 0; 134 }