题意:在一个n*m的矩阵里,每个格子都有一个灯,每个灯可以调节灯光大小,不超过所给的数字。给出每个灯的灯光大小,现要求把所有灯光调到同一个大小,小于这个大小的灯就关闭。要求每一个格子必须开着灯或者必须被东西方向和南北方向的灯同时照到。问这个大小最小是多少。
思路:并查集处理,枚举k的大小,那么每盏灯所照的大小(四个方向)为size+1(边界上的灯,为两个方向,为(size+1)/2)。
代码如下:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
using namespace std;
typedef long long LL;
const int maxn = 107;
int n, m, Map[107][10007], cnt;
int pax[10007][107], pay[107][10007];
int sizex[10007][107], sizey[107][10007];
struct Node {
int x, y, a;
Node() {}
Node(int x, int y, int a) : x(x),y(y),a(a) {}
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;
}
}node[1000007];
int Find_set(int pa[], int x) {
if(pa[x] == x) return x;
else return pa[x] = Find_set(pa, pa[x]);
}
void Union_set(int pa[], int siz[], int x, int y) {
int xx = Find_set(pa, x);
int yy = Find_set(pa, y);
if(siz[xx] < siz[yy]) swap(xx, yy);
siz[xx] += siz[yy];
pa[yy] = xx;
}
int solve() {
int Max = 0;
for(int k = 0, i = 0; i < cnt; ++k) {
if(k-1 >= Max) return k;
while(i < cnt && node[i].a == k) {
int x = node[i].x, y = node[i].y;
if(x-1 >= 1 && Map[x-1][y] <= k) Union_set(pax[y], sizex[y], x-1, x);
if(x+1 <= n && Map[x+1][y] < k) Union_set(pax[y], sizex[y], x, x+1);
if(y-1 >= 1 && Map[x][y-1] <= k) Union_set(pay[x], sizey[x], y-1, y);
if(y+1 <= m && Map[x][y+1] < k) Union_set(pay[x], sizey[x], y, y+1);
int xx = Find_set(pax[y], x);
int yy = Find_set(pay[x], y);
if(sizex[y][xx] == n || sizey[x][yy] == m) return -1;
if(Find_set(pax[y], 1) == xx || Find_set(pax[y], n) == xx)
Max = max(Max, sizex[y][xx]);
else Max = max(Max, (sizex[y][xx]+1)/2);
if(Find_set(pay[x], 1) == yy || Find_set(pay[x], m) == yy)
Max = max(Max, sizey[x][yy]);
else Max = max(Max, (sizey[x][yy]+1)/2);
++i;
// printf("Max: %d\n", Max);
}
}
return -1;
}
int main() {
while(~scanf("%d%d", &n, &m) && (n||m)) {
cnt = 0;
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
scanf("%d", &Map[i][j]);
node[cnt++] = Node(i, j, Map[i][j]);
}
}
sort(node, node+cnt);
for(int i = 1; i <= n; ++i) {
for(int j = 1; j <= m; ++j) {
pax[j][i] = i; sizex[j][i] = 1;
pay[i][j] = j; sizey[i][j] = 1;
}
}
int ans = solve();
if(ans == -1) printf("NO ANSWER!\n");
else printf("%d\n", ans);
}
}