谨以此题纪念我的第一次正式二分答案~
Tags: 二分答案 最小生成树 并查集
一个点每过一个单位时间就会向四个方向扩散一个距离,如图。
给出多个点的坐标,每个点会扩散成一个块,求所有的块连通的最早时刻。
注意
,不一定需要每两个块都直接导通。只要大家都融在一起了就行。另外,连通必须重合,邻接是不行的。具体见样例就明白了。
1 1 1 组。第一行一个数 N N N,接下来 N N N 行,每行一个点坐标 X [ i ] 和 Y [ i ] X[i]和Y[i] X[i]和Y[i]
对于 20 % 20\% 20% 的数据,满足 1 ≤ N ≤ 5 1≤N≤5 1≤N≤5; 1 ≤ X [ i ] , Y [ i ] ≤ 50 1≤X[i],Y[i]≤50 1≤X[i],Y[i]≤50;
对于 100 % 100\% 100% 的数据,满足 1 ≤ N ≤ 50 1≤N≤50 1≤N≤50; 1 ≤ X [ i ] , Y [ i ] ≤ 1 0 9 1≤X[i],Y[i]≤10^9 1≤X[i],Y[i]≤109。
输出一个数,表示所有的块连通的最早时刻。
2
0 0
1 2
2
2
0 0
5 5
5
此题最直接想到的应该是建最小生成树然后求里面的最长边就找到了答案。不过也可以二分答案找满足条件的最小距离。
当然不管怎么做,都得事先求一遍每两个点间的曼哈顿距离。不妨拿邻接矩阵来存。
#include <cstdio>
#include <cmath>
#include <cstring>
#define sc(x) {register char _c=getchar(),_v=1;for(x=0;_c<48||_c>57;_c=getchar())if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=getchar());x*=_v;}
#define PC putchar
#define M_DIST(u, v) (x[u]>x[v]?x[u]-x[v]:x[v]-x[u])+(y[u]>y[v]?y[u]-y[v]:y[v]-y[u])
template<typename T>void UPRT(const T a){if(a>=10)UPRT(a/10);PC(a%10+48);}
constexpr int MN(52);
int x[MN], y[MN];
int V, g[MN][MN];
int ds[MN];
int prim(const int SRC)
{
int max_min_d = -1;
for (int v=0; v<V; ++v)
ds[v] = g[SRC][v];
while (1)
{
int u = -1, min_d = 2e9+2333;
for (int v=1; v<V; ++v)
if (ds[v] && min_d > ds[v])
min_d = ds[u = v];
if (~u)
{
ds[u] = 0;
if (max_min_d < min_d)
max_min_d = min_d;
for (int v=1; v<V; ++v)
if (ds[v] && ds[v] > g[u][v])
ds[v] = g[u][v];
}
else break;
}
return max_min_d;
}
int main()
{
sc(V)
if (V == 1)
return PC('0'), 0;
for (int u=0; u<V; ++u)
{
sc(x[u])sc(y[u])
for (int v=0; v<u; ++v)
g[u][v] = g[v][u] = M_DIST(u, v);
}
int max_min_d = prim(0);
UPRT( (max_min_d+1) / 2 );
}
#include <cstdio>
#include <cstring>
#define sc(x) {register char _c=getchar(),_v=1;for(x=0;_c<48||_c>57;_c=getchar())if(_c==45)_v=-1;for(;_c>=48&&_c<=57;x=(x<<1)+(x<<3)+_c-48,_c=getchar());x*=_v;}
#define PC putchar
#define M_DIST(u, v) (x[u]>x[v]?x[u]-x[v]:x[v]-x[u])+(y[u]>y[v]?y[u]-y[v]:y[v]-y[u])
template<typename T>void UPRT(const T a){if(a>=10)UPRT(a/10);PC(a%10+48);}
constexpr int MN(52);
bool vis[MN];
int V, x[MN], y[MN];
template <const int MN>
class UF
{
public:
int uf[MN];
public:
UF(void) { }
inline void init(int V)
{
memset(uf, -1, (V+1) * sizeof(*uf));
}
int find(int x)
{
if (uf[x] >= 0)
uf[x] = find(uf[x]);
return uf[x];
}
void merge(int x, int y)
{
int r1 = find(x);
int r2 = find(y);
if (r1<r2)
{
uf[r1] += uf[r2];
uf[r2] = r1;
}
else if(r2<r1)
{
uf[r2] += uf[r1];
uf[r1] = r2;
}
}
bool connected(int x, int y)
{
return find(x) == find(y);
}
};
UF<MN> uf;
bool check(const int ANS)
{
uf.init(V);
for (int u=0; u<V; ++u)
for (int v=0; v<V; ++v)
if (M_DIST(u, v) <= ANS)
uf.merge(u, v);
const int ROOT = uf.find(0);
for (int u=0; u<V; ++u)
if (uf.find(u) != ROOT)
return false;
return true;
}
int binbin(int L, int R)
{
while (L <= R)
{
int mid = L + (R-L)/2;
if (check(mid))
R = mid-1;
else
L = mid+1;
}
return L;
}
int main()
{
sc(V)
if (V == 1)
return PC('0'), 0;
for (int u=0; u<V; ++u)
{
sc(x[u])sc(y[u])
}
int max_min_d= binbin(1, 1e9);
UPRT( (max_min_d+1) / 2 );
}