POJ 3241 曼哈顿距离最小生成树 Object Clustering

本文介绍了一种结合坐标变换和最小生成树算法解决特定几何问题的方法。通过四个方向的坐标变换,利用线段树进行区间查询,实现点集间的距离计算,并采用Kruskal算法求解最小生成树。

先上几个资料:

百度文库有详细的分析和证明

cxlove的博客

TopCoder Algorithm Tutorials

 

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <cmath>
using namespace std;

const int maxn = 10000 + 10;
const int INF = 0x3f3f3f3f;

int n, m, k;

struct Point
{
    int x, y, id;
    bool operator < (const Point& p) const {
        return x < p.x || (x == p.x && y < p.y);
    }
};

Point p[maxn];

int dist(Point a, Point b) { return abs(a.x-b.x) + abs(a.y-b.y); }

struct Node
{
    int min_val, pos;
    void init() { min_val = INF; pos = -1; }
};

inline int lowbit(int x) { return x & (-x); }

Node BIT[maxn];

struct Edge
{
    int u, v, d;
    Edge(int u, int v, int d):u(u), v(v), d(d) {}
    bool operator < (const Edge& e) const { return d < e.d; }
};

vector<Edge> edges;

int pa[maxn];
int findset(int x) { return x == pa[x] ? x : pa[x] = findset(pa[x]); }

int a[maxn], b[maxn];

void update(int x, int val, int pos) {
    while(x) {
        if(val < BIT[x].min_val) {
            BIT[x].min_val = val;
            BIT[x].pos = pos;
        }
        x -= lowbit(x);
    }
}

int query(int x) {
    int val = INF, pos = -1;
    while(x <= m) {
        if(BIT[x].min_val < val) {
            val = BIT[x].min_val;
            pos = BIT[x].pos;
        }
        x += lowbit(x);
    }
    return pos;
}

int main()
{
    //freopen("in.txt", "r", stdin);

    while(scanf("%d%d", &n, &k) == 2 && n)
    {
        edges.clear();
        for(int i = 0; i < n; i++) {
            scanf("%d%d", &p[i].x, &p[i].y);
            p[i].id = i;
        }

        //Select edges
        for(int dir = 0; dir < 4; dir++) {
            //Coordinate Transformation
            if(dir == 1 || dir == 3) for(int i = 0; i < n; i++) swap(p[i].x, p[i].y);
            else if(dir == 2) for(int i = 0; i < n; i++) p[i].x = -p[i].x;

            sort(p, p + n);
            for(int i = 0; i < n; i++) a[i] = b[i] = p[i].y - p[i].x;
            sort(b, b + n);
            m = 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 = lower_bound(b, b + m, a[i]) - b + 1;
                int q = query(pos);
                if(q != -1) edges.push_back(Edge(p[i].id, p[q].id, dist(p[i], p[q])));
                update(pos, p[i].x + p[i].y, i);
            }
        }

        //Kruskal
        sort(edges.begin(), edges.end());
        int cnt = n - k, ans;
        for(int i = 0; i < n; i++) pa[i] = i;
        for(int i = 0; i < edges.size(); i++) {
            int u = edges[i].u, v = edges[i].v;
            int pu = findset(u), pv = findset(v);
            if(pu != pv) {
                if(--cnt == 0) { ans = edges[i].d; break; }
                pa[pu] = pv;
            }
        }

        printf("%d\n", ans);
    }

    return 0;
}
代码君

 

转载于:https://www.cnblogs.com/AOQNRMGYXLMV/p/4834352.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值