POJ-3241 Object Clustering (Manhattan Minimum Spanning Tree)

Keywords: iOS

Title:

There are n point sets on the plane. Now divide them into k sets, so that each point in each set has at least one Manhattan distance between the points of this set not more than X, and find the minimum X.

Analysis:

The Title requires that the longest edge of the minimum spanning tree in Manhattan of each set should not exceed X after partitioning the set, so it is easy to think of the n-k edge of the minimum spanning tree in Manhattan of the entire set of points.

A brief description of the method for solving the minimum spanning tree of Manhattan distance:

If two or two points are directly edged, the total number of edges is O(n^2). With the time complexity O(N+E) Prim algorithm, the time complexity O(E*logE) kruskal algorithm will be timed out (where N is the number of points, E is the number of edges).

The idea here is to reduce the complexity of edges to O(n), because a large number of edges are useless, as long as the nearest point is connected every 45 degrees.

If B and C are in the right 45 degree area of y axis and | AB | <= | AC |, we can get | BC | <= | AC |, so | AB | + | BC | <= | AC | | AB or | AC|+|BC |, that is, the shortest distance between A, B and C is the sum of the shortest distance in every 45 degree direction (where the distance is Manhattan distance):

https://blog.csdn.net/huzecong/article/details/8576908

According to the above, we can only connect each point to the edge of the point with the smallest distance in eight directions.

Because the sides are bidirectional, we only need to connect R1, R2, R3 and R4. For example: (pictured above) B is the minimum distance point of A R1, A is the minimum distance point of B R5. We can know the relationship between AB as long as R 1 and R 5 are not connected, that is, A is connected to B.

The train of thought has come out, so how to deal with it? Let's first consider one direction, such as R1 (analogy of the other three directions).

Point B(x1,y1) in the region of point A(x0,y0) satisfies x1 (> x0) and Y1 X1 > Y0 x0. So B is on R1 of A.

The point closest to A in the R 1 region of A is also the point where x+y is the smallest among the points satisfying the conditions. So we can sort all the points in X coordinates and then disperse them in y_x.

Maintain the smallest x+y corresponding point (i.e. the smallest maintenance interval) of y_x larger than the current point with a line segment tree or tree array, and use a tree array here because the code is simpler.

Thus, the R1 region is processed, while the points of the other three regions need only be reversed and symmetrically transformed into the R1 region. For example, in R2 region, R3 can be obtained with respect to y=x symmetry (swap (x, y). Then R4 can be obtained with respect to X axis symmetry (x=-x), and R4 with respect to y=x symmetry.

//#include<bits/stdc++.h>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<iostream>

#define mm(a,b) memset(a,b,sizeof(a))
#define ACCELERATE (ios::sync_with_stdio(false),cin.tie(0))
#define pii pair<int,int>
#define pdd pair<double,double>
#define pll pair<long long,long long>
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define per(i,a,b) for(int i=(a);i>=(b);i--)
#define rush() int T;scanf("%d",&T);while(T--)
#define sc(a) scanf("%d",&a)
#define sc2(a,b) scanf("%d%d",&a,&b)
#define sc3(a,b,c) scanf("%d%d%d",&a,&b,&c)
#define pf(a) printf("%d\n",a)
#define pf2(a,b) printf("%d %d\n",a,b)
#define pf3(a,b,c) printf("%d %d %d\n",a,b,c)
#define debug(x) cout<<#x<<": "<<x<<endl
#define all(x) (x).begin(),(x).end()
#define PI acos(-1.0)
#define E exp(1.0)
#define ll long long
#define ld long double
#define ull unsigned long long
//#define io
using namespace std;

const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f;

int n,m,k;

const int maxn=1e4+10;

struct point{
    int x,y,id;
    bool operator < (const point& p) const{
        if(x==p.x) return y<p.y;
        return x<p.x;
    }
}p[maxn];

struct BIT{
    int pos,w;
    void init(){
        pos=-1;w=inf;
    }
}bit[maxn];

struct Edge{
    int u,v,w;
    bool operator <(const Edge& p) const{
        return w<p.w;
    }
}edge[maxn*100];

int tot;
int a[maxn],b[maxn];
int fa[maxn];

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

inline void addedge(int u,int v,int w){
    edge[++tot]=Edge{u,v,w};
}

int query(int x){
    int ans=inf,pos=-1;
    for(int i=x;i<=m;i+=lowbit(i)){
        if(bit[i].w<ans){
            ans=bit[i].w;
            pos=bit[i].pos;
        }
    }
    return pos;
}

void update(int x,int y,int pos){
    for(int i=x;i;i-=lowbit(i)){
        if(y<bit[i].w){
            bit[i].w=y;
            bit[i].pos=pos;
        }
    }
}

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

void solve(){
    sort(p+1,p+1+n);
    rep(i,1,n) a[i]=b[i]=p[i].y-p[i].x;
    sort(b+1,b+1+n);
    m=unique(b+1,b+1+n)-b-1;
    rep(i,1,n) a[i]=lower_bound(b+1,b+1+m,a[i])-b;
    rep(i,1,m) bit[i].init();
    per(i,n,1){
        int pos=query(a[i]);
        if(pos!=-1){
            addedge(p[i].id,p[pos].id,dist(p[i],p[pos]));
        }
        update(a[i],p[i].x+p[i].y,i);
    }
}

int find(int x){
    return x==fa[x]?x:fa[x]=find(fa[x]);
}

void kruskal(){
    sort(edge+1,edge+1+tot);
    rep(i,1,n) fa[i]=i;
    int cnt=0;
    rep(i,1,tot){
        int u=find(edge[i].u),v=find(edge[i].v);
        if(u!=v){
            cnt++;
            fa[u]=v;
        }
        if(cnt==k){
            pf(edge[i].w);
            return;
        }
    }
}

int main(){
    #ifdef io
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif

    sc2(n,k);
    k=n-k;
    rep(i,1,n) sc2(p[i].x,p[i].y),p[i].id=i;
    rep(i,0,3){
        if(i==1||i==3){
            rep(j,1,n) swap(p[j].x,p[j].y);
        }else if(i==2) rep(j,1,n) p[j].x=-p[j].x;
        solve();
    }
    kruskal();
    return 0;
}

 

Posted by phpdev12 on Wed, 11 Sep 2019 22:52:43 -0700