HDU 3688 Searchlights(并查集)
Problem Description
There is a piece of grids land of size n×m. Chandler and his team take responsibility to guard it. There are some searchlights on some pieces and each of them has a capability to lighten a distance towards four directions: north, south, east and west. Different searchlight has different lightening capability shown in levels. Searchlight with level k means that it can lighten k grids (including the gird that the searchlight stands in) along any of the four directions. Shown in following figure, there is a searchlight of level 3 and the shadow grids are ones that can be lightened by it. Particularly, searchlight of level 1 means that it can only lighten the grid in which the searchlight stands.
![](http://acm.hdu.edu.cn/data/images/3688-1.gif)
Each searchlight has a maximum level. You can decrease a searchlight’s level to save the energy. A searchlight whose maximum level is k can be turned to level k, k-1, k-2, …, 1 and 0. Level 0 means turning off the searchlight.
A grid is well-guarded if and only if at least one of the following two conditions is satisfied:
1.There is a searchlight in this grid, and it is not switched to level 0 (the light is on).
2.The grid is lightened by at least two searchlights. One lightens it in horizontal direction (east or west), and another lightens it in vertical direction (north or south).
Chandler asks you to help finding a solution that he can turn on some of the searchlights so that:
1.All the grids are well-guarded.
2.All the searchlights turned on are in a same level.
3.That same level mentioned above is as small as possible.
More specifically, if you choose a same level Q, then all the searchlights whose maximum level are less than Q have to be turned off. Please help him to find a solution with the minimum same level.
![](http://acm.hdu.edu.cn/data/images/3688-1.gif)
Each searchlight has a maximum level. You can decrease a searchlight’s level to save the energy. A searchlight whose maximum level is k can be turned to level k, k-1, k-2, …, 1 and 0. Level 0 means turning off the searchlight.
A grid is well-guarded if and only if at least one of the following two conditions is satisfied:
1.There is a searchlight in this grid, and it is not switched to level 0 (the light is on).
2.The grid is lightened by at least two searchlights. One lightens it in horizontal direction (east or west), and another lightens it in vertical direction (north or south).
Chandler asks you to help finding a solution that he can turn on some of the searchlights so that:
1.All the grids are well-guarded.
2.All the searchlights turned on are in a same level.
3.That same level mentioned above is as small as possible.
More specifically, if you choose a same level Q, then all the searchlights whose maximum level are less than Q have to be turned off. Please help him to find a solution with the minimum same level.
Input
The input file contains several test cases.
For each test case, the first line is two integers n and m, representing a grids land of size n×m. (0<n<=100, 0<m<=10000). Following n lines describe an n×m matrix in which ai,j means the maximum level of the searchlight in grid (i, j). ai,j can be zero, which means there is no searchlight on that grid. For all the cases, ai, j<=10000.
The input file ends with a line containing two zeros.
For each test case, the first line is two integers n and m, representing a grids land of size n×m. (0<n<=100, 0<m<=10000). Following n lines describe an n×m matrix in which ai,j means the maximum level of the searchlight in grid (i, j). ai,j can be zero, which means there is no searchlight on that grid. For all the cases, ai, j<=10000.
The input file ends with a line containing two zeros.
Output
For each test case, output a single line with an integer, representing the minimum level you have found. If there is no such a solution, output “NO ANSWER!”
题目大意:在一个n*m的矩阵里,每个格子都有一个灯,每个灯可以调节灯光大小(不超过上限)。给出每个灯的灯光大小,现要求把所有灯光调到同一个大小(小于这个大小的灯就不打开)。要求每一个格子必须开着灯或者必须被东西方向和南北方向的灯同时照到。问这个大小最小是多少。
思路:从小到大枚举灯光大小K,把所有小于K的灯依次灭了。用并查集维护所有没有开灯的地方,有多少个格子(每次灭掉一个灯,就把这个灯的左右的没有开灯的格子和自己的格子合并,上下同理),每一行每一列互不影响,各自维护即可。对于每一堆没有开灯的格子,设格子数为size,若他们挨着边界,那么灯光大小至少为size + 1(只有一边有灯照着);若没挨着边界,那么灯光大小至少为(size + 1) / 2(两边都有灯照着,一个要照一半的大小。若把所有灯都灭了都不行,输出NO ANSWER!。
代码(625MS):
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <queue> 6 using namespace std; 7 typedef long long LL; 8 9 const int MAXN = 110; 10 const int MAXM = 11000; 11 12 struct Node { 13 int a, x, y; 14 bool operator < (const Node &rhs) const { 15 if(a != rhs.a) return a < rhs.a; 16 if(x != rhs.x) return x < rhs.x; 17 return y < rhs.y; 18 } 19 } p[MAXN * MAXM]; 20 21 int mat[MAXN][MAXM]; 22 int xfa[MAXM][MAXN], yfa[MAXN][MAXM]; 23 int xsize[MAXM][MAXN], ysize[MAXN][MAXM]; 24 int n, m, s; 25 26 void init() { 27 for(int j = 1; j <= m; ++j) 28 for(int i = 1; i <= n; ++i) xfa[j][i] = i, xsize[j][i] = 1; 29 for(int i = 1; i <= n; ++i) 30 for(int j = 1; j <= m; ++j) yfa[i][j] = j, ysize[i][j] = 1; 31 } 32 33 int find_set(int *fa, int x) { 34 return fa[x] == x ? x : fa[x] = find_set(fa, fa[x]); 35 } 36 37 void merge(int *fa, int *size, int x, int y) { 38 int fx = find_set(fa, x), fy = find_set(fa, y); 39 if(size[fx] < size[fy]) swap(fx, fy); 40 size[fx] += size[fy]; 41 fa[fy] = fx; 42 } 43 44 int solve() { 45 int largest = 0; 46 for(int k = 0, i = 0; i < s; ++k) { 47 if(k - 1 >= largest) return k; 48 while(i < s && p[i].a == k) { 49 int x = p[i].x, y = p[i].y; 50 if(x - 1 >= 1 && mat[x - 1][y] <= k) merge(xfa[y], xsize[y], x - 1, x); 51 if(x + 1 <= n && mat[x + 1][y] < k) merge(xfa[y], xsize[y], x, x + 1); 52 if(y - 1 >= 1 && mat[x][y - 1] <= k) merge(yfa[x], ysize[x], y - 1, y); 53 if(y + 1 <= m && mat[x][y + 1] < k) merge(yfa[x], ysize[x], y, y + 1); 54 55 int fx = find_set(xfa[y], x), fy = find_set(yfa[x], y); 56 if(xsize[y][fx] == n || ysize[x][fy] == m) return -1; 57 58 if(find_set(xfa[y], 1) == fx || find_set(xfa[y], n) == fx) 59 largest = max(largest, xsize[y][fx]); 60 else largest = max(largest, (xsize[y][fx] + 1) / 2); 61 if(find_set(yfa[x], 1) == fy || find_set(yfa[x], m) == fy) 62 largest = max(largest, ysize[x][fy]); 63 else largest = max(largest, (ysize[x][fy] + 1) / 2); 64 65 ++i; 66 } 67 } 68 return -1; 69 } 70 71 int main() { 72 while(scanf("%d%d", &n, &m) != EOF) { 73 if(n == 0 && m == 0) break; 74 s = 0; 75 for(int i = 1; i <= n; ++i) { 76 for(int j = 1; j <= m; ++j) { 77 scanf("%d", &mat[i][j]); 78 p[s].x = i; 79 p[s].y = j; 80 p[s++].a = mat[i][j]; 81 } 82 } 83 sort(p, p + s); 84 init(); 85 int ans = solve(); 86 if(ans == -1) puts("NO ANSWER!"); 87 else printf("%d\n", ans); 88 } 89 }