ACM模版
曼哈顿最小生成树
POJ 3241 Object Clustering
简单说,他指两点之间的横纵坐标的差的绝对值之和。
题意
查找平面上的点的曼哈顿距离最小生成树的第n-k小边的长度,点数在100000以内。
解析
对于曼哈顿距离的最小生成树,朴素算法需要建立n^(n - 1)条边进行kruskal算法处理,这样子做一定会TLE的。所以需要做特殊的优化,将边数优化为4 * n条。
这里的优化涉及到一个与曼哈顿相关的性质:以任一一个点为端点,将平面分为八块,每块占45度角,那么在生成树的最优解中,每个块与这个点至多有一条边,即一个点最多分别向八个方向最近的点连接一条边,一条边两个点共用,所以最后边数为4 * n。
代码C++
#include <iostream>
#include <algorithm>
const int MAXN = 100010;
const int INF = 0x3f3f3f3f;
struct Point
{
int x;
int y;
int id;
}poi[MAXN];
bool cmp(Point a, Point b)
{
if (a.x != b.x)
{
return a.x < b.x;
}
else
{
return a.y < b.y;
}
}
struct BIT
{
int minVal;
int pos;
void init()
{
minVal = INF;
pos = -1;
}
}bit[MAXN];
struct Edge
{
int u;
int v;
int d;
}edge[MAXN << 2];
bool cmpEdge(Edge a, Edge b)
{
return a.d < b.d;
}
int tot;
int n;
int F[MAXN];
int find(int x)
{
if (F[x] == -1)
{
return x;
}
else
{
return F[x] = find(F[x]);
}
}
void addEdge(int u, int v, int d)
{
edge[tot].u = u;
edge[tot].v = v;
edge[tot++].d = d;
return ;
}
int lowbit(int x)
{
return x & (-x);
}
void update(int i, int val, int pos)
{
while (i > 0)
{
if (val < bit[i].minVal)
{
bit[i].minVal = val;
bit[i].pos = pos;
}
i -= lowbit(i);
}
return ;
}
int ask(int i, int m)
{
int minVal = INF;
int pos = -1;
while (i <= m)
{
if (bit[i].minVal < minVal)
{
minVal = bit[i].minVal;
pos = bit[i].pos;
}
i += lowbit(i);
}
return pos;
}
int dist(Point a, Point b)
{
return abs(a.x - b.x) + abs(a.y - b.y);
}
void ManhattanMinimumSpanningTree(int n, Point p[])
{
int a[MAXN], b[MAXN];
tot = 0;
for (int dir = 0; dir < 4; dir++)
{
if (dir == 1 || dir == 3)
{
for (int i = 0; i < n; i++)
{
std::swap(p[i].x, p[i].y);
}
}
else if (dir == 2)
{
for (int i = 0; i < n; i++)
{
p[i].x = -p[i].x;
}
}
std::sort(p, p + n, cmp);
for (int i = 0; i < n; i++)
{
a[i] = b[i] = p[i].y - p[i].x;
}
std::sort(b, b + n);
int m = (int)(std::unique(b, b + n) - b);
for (int i = 1; i <= m; i++)
{
bit[i].init();
}
for (int i = n - 1; i >= 0; i--)
{
int pos = (int)(std::lower_bound(b, b + m, a[i]) - b + 1);
int ans = ask(pos, m);
if (ans != -1)
{
addEdge(p[i].id, p[ans].id, dist(p[i], p[ans]));
}
update(pos, p[i].x + p[i].y, i);
}
}
return ;
}
int solve(int k)
{
ManhattanMinimumSpanningTree(n, poi);
memset(F, -1, sizeof(F));
std::sort(edge, edge + tot, cmpEdge);
for (int i = 0; i < tot; i++)
{
int u = edge[i].u;
int v = edge[i].v;
int tOne = find(u);
int tTwo = find(v);
if (tOne != tTwo)
{
F[tOne] = tTwo;
k--;
if (k == 0)
{
return edge[i].d;
}
}
}
return -1;
}
int main(int argc, const char * argv[])
{
int k;
while ((std::cin >> n >> k) && n)
{
for (int i = 0; i < n; i++)
{
std::cin >> poi[i].x >> poi[i].y;
poi[i].id = i;
}
std::cout << solve(n - k) << std::endl;
}
return 0;
}