Pro
Sol
好水的一道题啊……直接二分答案就可以过,不需要并查集的,二分加广搜,时间复杂度是O(n^2 logM),能过的。
读完题,我们很容易的就能知道,答案满足单调性,也就是说,如果mid能够到达一半以上,那么>mid的所有的数都可以达到一半以上,于是就会有一个临界值是达到和达不到之间的,这个值就是我们最终的答案。经分析得,本题满足二分条件,可以二分。二分出来,我们正着做广搜,搜索的路上就能求出最大的联通块,如果最大的联通块比一半要多,右端点移动,反之左端点移动。
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
void read(int &x)
{
char c = getchar(); x = 0;
while(c < '0' || c > '9') c = getchar();
while(c <= '9' && c >= '0') x = x*10+c-48, c = getchar();
}
void put(int x)
{
int num = 0; char c[15];
while(x) c[++num] = (x%10)+48, x /= 10;
while(num) putchar(c[num--]);
putchar('\n');
}
struct Node {
int x , y;
Node(){}
Node (int xx , int yy) {
x = xx , y = yy;
}
};
int n , map[505][505] , minn = 1e8 , maxx = -1 , vis[505][505] , K;
inline int mymax(int a , int b) { return a>b?a:b; }
inline int mymin(int a , int b) { return a<b?a:b; }
inline int myabs(int a) { return a>0?a:(-a); }
inline int mypow(int a , int b) { if(b == 1) return a; int t = mypow(a , b/2); if(b % 2 == 0) return t*t; return t*t*a; }
int bfs(int x , int y , int k) {
int res = 1;
vis[x][y] = 1;
queue<Node>q;
q.push(Node(x , y));
while(!q.empty()) {
Node u = q.front();
q.pop();
if(u.x-1>=1 && !vis[u.x-1][u.y] && myabs(map[u.x-1][u.y]-map[u.x][u.y])<=k) {
vis[u.x-1][u.y] = 1;
res++;
q.push(Node(u.x-1,u.y));
}
if(u.x+1<=n && !vis[u.x+1][u.y] && myabs(map[u.x+1][u.y]-map[u.x][u.y])<=k) {
vis[u.x+1][u.y] = 1;
res++;
q.push(Node(u.x+1,u.y));
}
if(u.y-1>=1 && !vis[u.x][u.y-1] && myabs(map[u.x][u.y-1]-map[u.x][u.y])<=k) {
vis[u.x][u.y-1] = 1;
res++;
q.push(Node(u.x,u.y-1));
}
if(u.y+1<=n && !vis[u.x][u.y+1] && myabs(map[u.x][u.y+1]-map[u.x][u.y])<=k) {
vis[u.x][u.y+1] = 1;
res++;
q.push(Node(u.x,u.y+1));
}
}
return res;
}
int jud(int x) {
int ans = 0;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++)
if(!vis[i][j])
ans = mymax(ans , bfs(i,j,x));
if(ans >= K)
return 1;
return 0;
}
int main() {
read(n);
K = mypow(n , 2) / 2;
for(int i=1; i<=n; i++)
for(int j=1; j<=n; j++) {
read(map[i][j]);
minn = mymin(minn , map[i][j]);
maxx = mymax(maxx , map[i][j]);
}
int l = 0 , r = maxx - minn;
while(l <= r) {
memset(vis , 0 , sizeof(vis));
int mid = (l+r)>>1;
if(jud(mid))
r = mid - 1;
else
l = mid + 1;
}
put(l);
return 0;
}