POJ3241 Object Clustering 曼哈顿最小生成树

题意:转换一下就是求曼哈顿最小生成树的第n-k条边

参考:莫涛大神的论文《平面点曼哈顿最小生成树》

/*
Problem: 3241        User: 96655
Memory: 920K        Time: 94MS
Language: C++        Result: Accepted
*/
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cmath>
using namespace std;
typedef long long LL;
const int maxn=10005;
const int INF=0x3f3f3f3f;
const int maxm=4015;
int n,k,p;
struct Point
{
    int x,y,id;
    bool operator<(const Point &e)const
    {
        if(x==e.x)return y<e.y;
        return x<e.x;
    }
} point[maxn];
struct Edge
{
    int u,v,w;
    bool operator<(const Edge &e)const
    {
        return w<e.w;
    }
} edge[maxn*10];
void addedge(int a,int b,int l,int r)
{
    ++p;
    edge[p].u=a;
    edge[p].v=b;
    edge[p].w=abs(l-r);
}
struct Node
{
    int len,id;
} node[(maxm+10)<<2];
void pushup(int rt)
{
    node[rt].len=min(node[rt*2].len,node[rt*2+1].len);
    if(node[rt].len==node[rt*2].len)node[rt].id=node[rt*2].id;
    else node[rt].id=node[rt*2+1].id;
}
void change(int rt,int l,int r,Point tt)
{
    if(l==r)
    {
        node[rt].len=tt.x+tt.y;
        node[rt].id=tt.id;
        return;
    }
    int pos=tt.y-tt.x+1005;
    int m=(l+r)>>1;
    if(pos<=m)change(rt*2,l,m,tt);
    else change(rt*2+1,m+1,r,tt);
    pushup(rt);
}
Node query(int rt,int l,int r,int x,int y)
{
    if(x<=l&&r<=y)
        return node[rt];
    int m=(l+r)>>1;
    if(y<=m)return query(rt*2,l,m,x,y);
    else if(x>m)return query(rt*2+1,m+1,r,x,y);
    else
    {
        Node t1,t2;
        t1=query(rt*2,l,m,x,y);
        t2=query(rt*2+1,m+1,r,x,y);
        if(t1.len<t2.len)return t1;
        else return t2;
    }
}
int fa[maxn];
int find(int x)
{
    if(x==fa[x])return x;
    return fa[x]=find(fa[x]);
}
void init()
{
    for(int i=0; i<(maxm<<2); ++i)
        node[i].len=INF,node[i].id=-1;
}
void build()
{
    sort(point+1,point+1+n);
    init();
    for(int i=n; i>0; --i)
    {
        int s=point[i].x+point[i].y;
        Node t=query(1,1,maxm,point[i].y-point[i].x+1005,maxm);
        if(t.id!=-1)
            addedge(point[i].id,t.id,s,t.len);
        change(1,1,maxm,point[i]);
    }

}
int solve()
{
    sort(edge+1,edge+p+1);
    int cnt=0;
    for(int i=1; i<=p; ++i)
    {
        int fx=find(edge[i].u);
        int fy=find(edge[i].v);
        if(fx!=fy)
        {
            fa[fy]=fx;
            ++cnt;
            if(cnt==n-k)return edge[i].w;
        }
    }
}
int main()
{
    scanf("%d%d",&n,&k);
    for(int i=1; i<=n; ++i)
        scanf("%d%d",&point[i].x,&point[i].y),point[i].id=i;
    for(int i=1; i<=n; ++i)
        fa[i]=i;
    p=0;
    build();
    for(int i=1; i<=n; ++i)
        point[i].y=-point[i].y;
    build();
    for(int i=1; i<=n; ++i)
        point[i].y=-point[i].y,swap(point[i].x,point[i].y);
    build();
    for(int i=1; i<=n; ++i)
        point[i].y=-point[i].y;
    build();
    printf("%d\n",solve());
    return 0;
}

时间: 2024-12-28 16:10:14

POJ3241 Object Clustering 曼哈顿最小生成树的相关文章

poj 3241 Object Clustering 曼哈顿最小生成树

题意: 平面上有n个点,现在把他们分成k个集合,使得每个集合中的每个点都至少有一个本集合的点之间的曼哈顿距离不大于X,求最小的X. 分析: 转化为求n个点生成完全图的最小生成树的第k大边.接下来有几个重点. 1)根据莫队算法,由于边权是点的曼哈顿距离,每个点只需要跟周围8个方向中每个方向最近的点连边,这样算出的图与用完全图算出的最小生成树一样,涉及的边却大大减少. 2)用树状数组维护y右偏45度的最近点,每个点以y-x的位置,y+x的值放入树状数组,由于每次是查询区间(pos,last)的情况,

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

题目大意:求出曼哈顿距离最小生成树上的第k大边权. 思路:首先,你要了解:http://blog.csdn.net/acm_cxlove/article/details/8890003 也就是说,我们以每一个点为中心,把平面分成8个部分,每一个部分我们只需要离这个点最近的点.然后加上建一条边连接这个边和最近的点.然后就是MST. 听说这个算法是莫队算法的基础,我现在就去学. CODE: #include <cstdio> #include <cstring> #include &l

平面点曼哈顿最小生成树——POJ 3241 Object Clustering

对应POJ题目:点击打开链接 Object Clustering Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 1697   Accepted: 418 Description We have N (N ≤ 10000) objects, and wish to classify them into several groups by judgement of their resemblance. To simply

poj 3241 Object Clustering (曼哈顿最小生成树)

Object Clustering Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 2640   Accepted: 806 Description We have N (N ≤ 10000) objects, and wish to classify them into several groups by judgement of their resemblance. To simply the model, each

POJ 3241 Object Clustering 莫队算法

第n-k大曼哈顿距离,莫队算法裸题 Object Clustering Time Limit: 2000MS   Memory Limit: 131072K Total Submissions: 1584   Accepted: 366 Description We have N (N ≤ 10000) objects, and wish to classify them into several groups by judgement of their resemblance. To simp

曼哈顿最小生成树

1.poj 3241 Object Clustering 题意:平面上有n个点,点之间的距离采用曼哈顿距离衡量.求一个最小距离X,使得在把这些点分为k组后,每组中两两点之间的距离不超过X. 思路:首先我们这么想,如果所有点都在1个组中,即k=1时,那么所要求的X即为该n个点的曼哈顿最小生成树的最大边:当k=2时,如果我们将最小生成树的最大边割开,形成2组,答案仍未原最小生成树的第2大的边(不会比之还小)……以此类推,可转换为求解平面上n个点的曼哈顿距离最小生成树的第k大的边的长度. 接下来,就是

曼哈顿最小生成树 全网最全

好消息,为庆祝自己暑假上蓝,并成功晋级为参赛队员.我决定在这个暑假集训中写一篇研究性报告,像那些国家集训队的人那样,当然质量没有那么高.我假装网上没有直接完整的关于曼哈顿最小生成树资料.于是自己就想做整理和详细解释的工作.后文会放上自己参考的blog,喝水不忘挖井人. 摘    要: 曼哈顿最小生成树,是把最小生成树中两点直线距离的条件改成了在坐标系下的曼哈顿距离的条件. 结    论: 以一个点为原点建立直角坐标系,在每45度内只会向距离该点最近的一个点连边. 算法过程: 我直接就按照算法ru

【POJ 3241】曼哈顿最小生成树(模板整理)

关于 曼哈顿最小生成树 的证明见:http://www.2cto.com/kf/201505/399861.html 模板: #include<cmath> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; const int MAXN = 100010; const int INF = 0x3f3f3f3f; struct Point{ int x,y,i

POJ 3241 Object Clustering 二维平面曼哈顿距离最小生成树

题目链接:点击打开链接 题意: 给定二维平面上的n个点坐标,常数k 下面n行给出坐标 求一个最小生成树,问第k大的边是多少. 任意两个点间建一条边的花费是其曼哈顿距离. 思路:转自:点击打开链接 一.曼哈顿距离最小生成树 曼哈顿距离最小生成树问题可以简述如下: 给定二维平面上的N个点,在两点之间连边的代价为其曼哈顿距离,求使所有点连通的最小代价. 朴素的算法可以用O(N2)的Prim,或者处理出所有边做Kruskal,但在这里总边数有O(N2)条,所以Kruskal的复杂度变成了O(N2logN