POJ 3241 曼哈顿最小生成树

感觉讲解,写的非常详细,http://blog.csdn.net/huzecong/article/details/8576908

重点是一个定理: Hint For the graph on the right, there exists a minimum spanning tree in which there is at most one vertex connected with A in the shadow area. You can extend this property to solve the problem.

#include<cstdio>
#include<algorithm>
#define N 100010
#define INF 0x3f3f3f3f

using namespace std;

struct point
{
    int x,y,id;
    bool operator<(const point &p) const
    { return x==p.x?y<p.y:x<p.x;}
}p[N];
struct edge
{
    int a,b,w;
    bool operator<(const edge &x) const
    { return w<x.w;}
}e[N<<2];
struct BIT
{
    int w,p;
}bit[N];

int n,k,m,tot,ans;
int f[N],a[N],b[N];

int abs(int x)
{
    return x<0?-x:x;
}

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

int query(int x)
{
    int r=INF,p=-1;
    while(x<=m)
    {
        if (bit[x].w<r) r=bit[x].w,p=bit[x].p;
        x+=x&-x;
    }
    return p;
}

void update(int x, int w, int p)
{
    while(x>0)
    {
        if (bit[x].w>w) bit[x].w=w,bit[x].p=p;
        x-=x&-x;
    }
}

void addedge(int a, int b, int w)
{
    ++tot;
    e[tot].a=a,e[tot].b=b,e[tot].w=w;
}

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

int main()
{
    while(scanf("%d%d",&n,&k)!=EOF)
    {
        tot=0;
        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+n+1);

            for (int i=1;i<=n;i++) 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;
            for (int i=1;i<=n;i++) a[i]=lower_bound(b+1,b+m+1,a[i])-b;

            for (int i=1;i<=m;i++) bit[i].w=INF,bit[i].p=-1;
            for (int i=n;i>=1;i--)
            {
                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);
            }
        }
        sort(e+1,e+tot+1);
        for (int i=1;i<=n;i++) f[i]=i;
        for (int i=1,ec=n;ec>k&&i<=tot;i++)
            if (find(e[i].a)!=find(e[i].b))
        {
            f[find(e[i].a)]=find(e[i].b);
            if (--ec==k) ans=e[i].w;
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

时间: 2024-08-02 17:53:35

POJ 3241 曼哈顿最小生成树的相关文章

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

对应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】曼哈顿最小生成树(模板整理)

关于 曼哈顿最小生成树 的证明见: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 (曼哈顿最小生成树)

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

http://poj.org/problem?id=3241 曼哈顿距离最小生成树模板题. 核心思想是把坐标系转3次,以及以横坐标为第一关键字,纵坐标为第二关键字排序后,从后往前扫.扫完一个点就把它插到树状数组的x-y位置上,权值为x+y.查询时查询扫过的所有点满足xdone-ydone>=xnow-xnow时,直接是树状数组中的的一个后缀区间,从后往前扫保证了区间内的这些点都在当前点的y轴向右扫45度的范围内.树状数组实现查询x+y的最小值,以及此最小值对应原数组中的位置,方便建图连边. 模板

曼哈顿最小生成树

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

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

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

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<cs

poj 1679 判断最小生成树是否唯一

/* 只需判断等效边和必选边的个数和n-1的关系即可 */ #include<stdio.h> #include<stdlib.h> #define N 110 struct node { int u,v,w; }f[N*N*2]; int cmp(const void *a,const void*b) { return (*(struct node *)a).w-(*(struct node *)b).w; } int pre[N]; int find(int x) { if(x