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.

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.

 
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):
 #include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL; const int MAXN = ;
const int MAXM = ; struct Node {
int a, x, y;
bool operator < (const Node &rhs) const {
if(a != rhs.a) return a < rhs.a;
if(x != rhs.x) return x < rhs.x;
return y < rhs.y;
}
} p[MAXN * MAXM]; int mat[MAXN][MAXM];
int xfa[MAXM][MAXN], yfa[MAXN][MAXM];
int xsize[MAXM][MAXN], ysize[MAXN][MAXM];
int n, m, s; void init() {
for(int j = ; j <= m; ++j)
for(int i = ; i <= n; ++i) xfa[j][i] = i, xsize[j][i] = ;
for(int i = ; i <= n; ++i)
for(int j = ; j <= m; ++j) yfa[i][j] = j, ysize[i][j] = ;
} int find_set(int *fa, int x) {
return fa[x] == x ? x : fa[x] = find_set(fa, fa[x]);
} void merge(int *fa, int *size, int x, int y) {
int fx = find_set(fa, x), fy = find_set(fa, y);
if(size[fx] < size[fy]) swap(fx, fy);
size[fx] += size[fy];
fa[fy] = fx;
} int solve() {
int largest = ;
for(int k = , i = ; i < s; ++k) {
if(k - >= largest) return k;
while(i < s && p[i].a == k) {
int x = p[i].x, y = p[i].y;
if(x - >= && mat[x - ][y] <= k) merge(xfa[y], xsize[y], x - , x);
if(x + <= n && mat[x + ][y] < k) merge(xfa[y], xsize[y], x, x + );
if(y - >= && mat[x][y - ] <= k) merge(yfa[x], ysize[x], y - , y);
if(y + <= m && mat[x][y + ] < k) merge(yfa[x], ysize[x], y, y + ); int fx = find_set(xfa[y], x), fy = find_set(yfa[x], y);
if(xsize[y][fx] == n || ysize[x][fy] == m) return -; if(find_set(xfa[y], ) == fx || find_set(xfa[y], n) == fx)
largest = max(largest, xsize[y][fx]);
else largest = max(largest, (xsize[y][fx] + ) / );
if(find_set(yfa[x], ) == fy || find_set(yfa[x], m) == fy)
largest = max(largest, ysize[x][fy]);
else largest = max(largest, (ysize[x][fy] + ) / ); ++i;
}
}
return -;
} int main() {
while(scanf("%d%d", &n, &m) != EOF) {
if(n == && m == ) break;
s = ;
for(int i = ; i <= n; ++i) {
for(int j = ; j <= m; ++j) {
scanf("%d", &mat[i][j]);
p[s].x = i;
p[s].y = j;
p[s++].a = mat[i][j];
}
}
sort(p, p + s);
init();
int ans = solve();
if(ans == -) puts("NO ANSWER!");
else printf("%d\n", ans);
}
}

HDU 3688 Searchlights(并查集)的更多相关文章

  1. HDU 2818 (矢量并查集)

    题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2818 题目大意:每次指定一块砖头,移动砖头所在堆到另一堆.查询指定砖头下面有几块砖头. 解题思路: ...

  2. hdu 1116 欧拉回路+并查集

    http://acm.hdu.edu.cn/showproblem.php?pid=1116 给你一些英文单词,判断所有单词能不能连成一串,类似成语接龙的意思.但是如果有多个重复的单词时,也必须满足这 ...

  3. Bipartite Graph hdu 5313 bitset 并查集 二分图

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5313 题意: 给出n个顶点,m条边,问最多添加多少条边使之构成一个完全二分图 存储结构: bitset   ...

  4. hdu 3081(二分+并查集+最大流||二分图匹配)

    Marriage Match II Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others ...

  5. 2015 ACM/ICPC Asia Regional Changchun Online HDU - 5441 (离线+并查集)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=5441 题意:给你n,m,k,代表n个城市,m条边,k次查询,每次查询输入一个x,然后让你一个城市对(u,v ...

  6. hdu 3536【并查集】

    hdu 3536 题意: 有N个珠子,第i个珠子初始放在第i个城市.有两种操作: T A B:把A珠子所在城市的所有珠子放到B城市.  Q A:输出A珠子所在城市编号,该城市有多少个珠子,该珠子转移了 ...

  7. HDU 1829 分组并查集

    题意:有两种性别,每组数据表示是男女朋友,判断输入的几组数据是否有同性恋 思路:http://blog.csdn.net/iaccepted/article/details/24304087 分组并查 ...

  8. HDU 1198(并查集)

    题意:给你11个图,每一个都有管道,然后给一张由这11个正方形中的n个组成的图,判断有几条连通的管道: 思路:在大一暑假的时候做过这道题,当时是当暴力来做的,正解是并查集,需要进行一下转换: 转换1: ...

  9. HDU 4496 D-City(并查集,逆思维)

    题目 熟能生巧...常做这类题,就不会忘记他的思路了... //可以反过来用并查集,还是逐个加边,但是反过来输出...我是白痴.....又没想到 //G++能过,C++却wa,这个也好奇怪呀... # ...

随机推荐

  1. QTSingleApplication使用笔记

    http://www.cnblogs.com/kevinzhwl/archive/2012/08/27/2658839.html QTSingleApplication,是Qt官方提供的,用于实现只启 ...

  2. 1014 C语言文法

    <程序> -> <外部声明> | <程序> <外部声明> <外部声明> -> <函数定义> | <声明> ...

  3. Qt工具知多少(一目了然)

    一级题目: Qt Designer — 所见即所得的界面设计工具, 可以用拖拽的方式将控件排布在界面上,支持layout, 支持signal/slot编辑. 生成的文件保存为ui格式, ui是xml格 ...

  4. Ubuntu 设置Vim tab为四个空格

    使用root权限打开 /etc/vim/vimrc 添加下列配置 set tabstop= set softtabstop= set shiftwidth= set noexpandtab set n ...

  5. Spark Programming--Fundamental operation

    max max(key=None) Find the maximum item in this RDD. Parameters:key – A function used to generate ke ...

  6. Dancing Stars on Me---hdu5533(判断是否为正多边形)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5533 题意:平面图中 有n个点给你每个点的坐标,判断是否能通过某种连线使得这些点所组成的n边形为 正n ...

  7. Swift 遇到的报错信息

    第一个,没看懂.一开始还以为是不支持iOS7的缘故. dyld: Library not loaded: @rpath/libswiftCore.dylib Referenced from: /var ...

  8. Java学习-024-获取当前类名或方法名二三文

    今天,看朋友编写程序,打印日志时,需要记录当前类的类名以及当前方法的方法名,我发现 TA 将类名或者方法名直接写死在了代码中...虽说这样可以实现记录类名和方法名,但是当有特殊情况需要修改类名或者方法 ...

  9. c# 过滤字符串中的重复字符

    有字符串"a,s,d,v,a,v",如果想去除其中重复的字符,怎么做? 下面是一个方法,用Hashtable来记录唯一字符,排除重复字符,仅供参考. 1.过滤方法: public ...

  10. 10月26日 奥威Power-BI基于微软示例库(MSOLAP)快速制作管理驾驶舱 腾讯课堂开课啦

    本次课是基于olap数据源的案例实操课,以微软olap示例库Adventure Works为数据基础.        AdventureWorks示例数据库为一家虚拟公司的数据,公司背景为大型跨国生产 ...