POJ 3241 Object Clustering 曼哈顿距离求最小生成树的第K小边

转自:http://blog.csdn.net/huzecong/article/details/8576908


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#define lowbit(x) (x&(-x))
#define inf 0x3f3f3f3f
#define maxn 10005
using namespace std;

struct point
{
    int x,y,id;
    bool operator < (const point &cmp)const
    {
        if(x==cmp.x)return y<cmp.y;
        return x<cmp.x;
    }
} p[maxn];
struct BIT
{
    int min_val,pos;
    void init()
    {
        min_val=inf;
        pos=-1;
    }
} bit[maxn];
struct Edge
{
    int s,e,w;
    bool operator < (const Edge &cmp)const
    {
        return w<cmp.w;
    }
} E[maxn<<2];
int tot,n,k;
void update(int x,int val,int pos)//更新 1-x  上的最小值
{
    for(int i=x; i>=1; i-=lowbit(i))
        if(bit[i].min_val >  val)
            bit[i].min_val=val,bit[i].pos=pos;
}
int query(int x,int m)//这里其实求的是 x-m 上的最小值
{
    int val=inf,pos=-1;
    for(int i=x; i<=m; i+=lowbit(i))
        if(bit[i].min_val < val)
            val=bit[i].min_val,pos=bit[i].pos;
    return pos;
}
void addedge(int s,int e,int v)
{
    E[tot].s=s;
    E[tot].e=e;
    E[tot++].w=v;
}
int dist(int a,int b)
{
    return abs(p[a].x-p[b].x)+abs(p[a].y-p[b].y);
}
int set[maxn];
int find(int x)
{
    if(x!=set[x])
        return set[x]=find(set[x]);
    return x;
}
int a[maxn],b[maxn];
int Manhattan_MST()
{
    for(int i=1; i<=n; i++)
    {
        scanf("%d%d",&p[i].x,&p[i].y);
        p[i].id=i;
    }

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

        sort(p+1,p+1+n);//sort by x

        for(int i=1; i<=n; i++)
            a[i]=b[i]=p[i].y-p[i].x;

        sort(b+1,b+1+n);//将 y-x 离散化

        int m=unique(b+1,b+1+n)-b;

        for(int i=1; i<m; i++)bit[i].init();

        for(int i=n; i>=1; i--)//这里y-x从大到小进入BIT。那么这里保证了y-x 的有序。
        {
            int pos=lower_bound(b+1,b+m,a[i])-b;
            int ans = query(pos,m-1);
            if(ans!=-1)addedge(p[i].id,p[ans].id,dist(i,ans));
            update(pos,p[i].x+p[i].y,i);//求出加入到BIT中的比当前点y-x大的y+x的值。
        }
    }
    sort(E,E+tot);

    for(int i=0; i<=n; i++)set[i]=i;

    int cnt=n-k;

    for(int i=0; i<tot; i++)
    {
        int x=find(E[i].s);
        int y=find(E[i].e);
        if(x==y)continue;
        else
        {
            set[x]=y;
            cnt--;
            if(cnt==0)return E[i].w;
        }
    }
}
int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        tot=0;
        printf("%d\n",Manhattan_MST());
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值