POJ--3241(曼哈顿距离,MST)

2015-04-29 21:58:58

题目:题意有先争议... 其实出题人就是想考:求曼哈顿距离最小生成树上的第K大的边。

  关于 manhattan mst 的介绍:博客

  然后就是比较裸的问题了... 最后用kruskal找第K大的边。

  过程基本上可以简述为:

  (1)将所有点经历四种变换【不变,y=x对称,y=0对称,y=x对称】

  (2)对于每种变换,要找出每个点在 y 轴向右45度的1/8象限区域内最近的点。

      首先对所有点按 x 排序,再把 y- x离散化(若数据大),然后对于每个点用树状数组求出 y-x 比该点大且 x+y 最小的点,两点建边。

  (3)根据建的边跑一遍Kruskal,找第 N-K 条边即可。

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <stack>
#include <queue>
#include <string>
#include <iostream>
#include <algorithm>
using namespace std;

#define MEM(a,b) memset(a,b,sizeof(a))
#define REP(i,n) for(int i=0;i<(n);++i)
#define FOR(i,a,b) for(int i=(a);i<=(b);++i)
#define getmid(l,r) ((l) + ((r) - (l)) / 2)
#define MP(a,b) make_pair(a,b)
#define PB(a) push_back(a)

typedef long long ll;
typedef pair<int,int> pii;
const double eps = 1e-8;
const int INF = (1 << 30) - 1;
const int MAXN = 10010;

int N,K;
int fa[MAXN],A[MAXN],B[MAXN];
int ecnt;

struct edge{
    int u,v,c;
    bool operator < (const edge a) const{
        return c < a.c;
    }
}e[4 * MAXN];

void Add_edge(int u,int v,int c){
    e[++ecnt].u = u;
    e[ecnt].v = v;
    e[ecnt].c = c;
}

struct Node{
    int x,y,id;
    bool operator < (const Node a) const{
        return x == a.x ? y < a.y : x < a.x;
    }
}p[MAXN];

struct BIT{
    int c[MAXN],ps[MAXN],tmax;
    void init(int tmp){
        tmax = tmp;
        FOR(i,1,tmax) c[i] = INF;
        MEM(ps,-1);
    }
    int lowbit(int x){ return x & (-x); }
    void update(int x,int d,int pos){
        while(x){
            if(d < c[x]){
                c[x] = d;
                ps[x] = pos;
            }
            x -= lowbit(x);
        }
    }
    int get(int x){
        int res = INF,pos = -1;
        while(x <= tmax){
            if(c[x] < res){
                res = c[x];
                pos = ps[x];
            }
            x += lowbit(x);
        }
        return pos;
    }
}bit;

int Dis(int a,int b){ return abs(p[a].x - p[b].x) + abs(p[a].y - p[b].y); }
int Find(int x){ return fa[x] == x ? x : fa[x] = Find(fa[x]); }

int Manhattan_mst(){
    for(int dir = 1; dir <= 4; ++dir){
        //四种变换:(1) none , (2) y=x , (3) y=0 , (4) y=x
        if(dir == 2 || dir == 4)
            FOR(i,1,N) swap(p[i].x,p[i].y);
        else if(dir == 3)
            FOR(i,1,N) p[i].y = -p[i].y;
        sort(p + 1,p + N + 1); //sort by x
        FOR(i,1,N) A[i] = B[i] = p[i].y - p[i].x; //离散化
        sort(B + 1,B + N + 1);
        int sz = unique(B + 1,B + N + 1) - B - 1;
        //初始化反树状数组
        bit.init(sz);
        for(int i = N; i >= 1; --i){ //从 x 大的开始考虑
            int pos = lower_bound(B + 1,B + sz + 1,A[i]) - B;
            int ans = bit.get(pos); //比当前 y-x 大的最小 x+y 位置
            if(ans != -1) Add_edge(p[i].id,p[ans].id,Dis(i,ans));//i找到匹配ans
            bit.update(pos,p[i].x + p[i].y,i);
        }
    }
    //Kruskal
    sort(e + 1,e + ecnt + 1);
    int cnt = N - K;
    FOR(i,1,N) fa[i] = i;
    FOR(i,1,ecnt){
        int x = Find(e[i].u);
        int y = Find(e[i].v);
        if(x != y){
            fa[y] = x;
            cnt--;
            if(cnt == 0) return e[i].c;
        }
    }
}

int main(){
    while(scanf("%d%d",&N,&K) != EOF){
        FOR(i,1,N){
            scanf("%d%d",&p[i].x,&p[i].y);
            p[i].id = i;
        }
        ecnt = 0;
        printf("%d\n",Manhattan_mst());
    }
    return 0;
}

 

posted @ 2015-04-29 22:23  Naturain  阅读(142)  评论(0编辑  收藏  举报