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

Posted acboyty

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj 3241 Object Clustering (曼哈顿最小生成树)相关的知识,希望对你有一定的参考价值。

Object Clustering
Time Limit: 2000MS   Memory Limit: 131072K
Total Submissions: 2640   Accepted: 806

Description

We have (N ≤ 10000) objects, and wish to classify them into several groups by judgement of their resemblance. To simply the model, each object has 2 indexes a and b (ab ≤ 500). The resemblance of object i and object j is defined by dij = |a- aj| + |b- bj|, and then we say i is dij resemble to j. Now we want to find the minimum value of X, so that we can classify the Nobjects into K (< N) groups, and in each group, one object is at most X resemble to another object in the same group, i.e, for every object i, if i is not the only member of the group, then there exists one object j (i ≠ j) in the same group that satisfies dij ≤ X

Input

The first line contains two integers N and K. The following N lines each contain two integers a and b, which describe a object.

Output

A single line contains the minimum X.

Sample Input

6 2
1 2
2 3
2 2
3 4
4 3
3 1

Sample Output

2

 

题目大意:

(在平面坐标第一象限)给你n个整点,A(x1,y1)和B(x2,y2)两点之间的距离定义为|x1-x2|+|y1-y2|,求最小生成树第k大边。

 

曼哈顿最小生成树经典题。

首先这道题条件给的不充分啊:点都在第一象限(不包括坐标轴),没有重(chong)点。

大致理一下思路:

首先,如果将点两两相连,边数是O(n^2)的。但并非所有的边都有用。网上有很多相关的证明,可以证得,只需对一二象限均分的四个部分分别求最近的点加边。

其次,怎么处理呢。先考虑y轴左偏45度的那一块。先对y-x离散化,再对x排序(排序函数要注意,因为要把边界算上),这样每次查询y-x和x比当前点大的点中最小值就好了(用线段树)。这一块实现起来确实比较麻烦,详见代码。

再次,其余三个部分通过坐标变换就可以套用第一部分的处理方式了。(x,y)(y,x)(-y,x)(x,-y)。

最后,跑个kruskal就ok了。

 

技术分享图片
#include<cstdio>
#include<algorithm>

using namespace std;

const int maxn=10000;
const int inf=10000;

struct tdot
{
    int x,y;
    int num;//每个点的序号
    int dis;//离散化后的值
};
tdot dot[maxn+10];

//x
int cmp1(tdot a,tdot b)
{
    if(a.x==b.x)
        return a.y<b.y;
    return a.x<b.x;
}

//y-x
int cmp2(tdot a,tdot b)
{
    if(a.y-a.x==b.y-b.x)
        return a.x<b.x;
    return a.y-a.x<b.y-b.x;
}

//离散化及预处理
void discrete(int n)
{
    sort(dot+1,dot+n+1,cmp2);
    for(int i=1;i<=n;i++)
        dot[i].dis=i;
    sort(dot+1,dot+n+1,cmp1);
}

struct ttree
{
    int l,r;
    int num;
    int mmin;
};
ttree tree[maxn*4+10];

void pushup(int x)
{
    if(tree[x].l==tree[x].r)
        return;
    if(tree[x*2].mmin<=tree[x*2+1].mmin)
        tree[x].mmin=tree[x*2].mmin,tree[x].num=tree[x*2].num;
    else
        tree[x].mmin=tree[x*2+1].mmin,tree[x].num=tree[x*2+1].num;
}

void build(int x,int l,int r)
{
    tree[x].l=l;tree[x].r=r;
    tree[x].mmin=inf;
    tree[x].num=0;
    if(l<r)
    {
        int mid=(l+r)/2;
        build(x*2,l,mid);
        build(x*2+1,mid+1,r);
    }
}

void modify(int x,int pos,int mmin,int num)
{
    if(tree[x].l==tree[x].r)
        tree[x].mmin=mmin,tree[x].num=num;
    else
    {
        int mid=(tree[x].l+tree[x].r)/2;
        if(pos<=mid)
            modify(x*2,pos,mmin,num);
        else
            modify(x*2+1,pos,mmin,num);
        pushup(x);
    }
}

struct tret
{
    int mmin,num;
};

tret query(int x,int l,int r)
{
    tret ret;
    ret.mmin=inf;ret.num=0;
    if(l<=tree[x].l&&r>=tree[x].r)
    {
        ret.mmin=tree[x].mmin;
        ret.num=tree[x].num;
        return ret;
    }
    int mid=(tree[x].l+tree[x].r)/2;
    if(l<=mid)
    {
        tret ret0=query(x*2,l,r);
        if(ret.mmin>ret0.mmin)
            ret.mmin=ret0.mmin,ret.num=ret0.num;
    }
    if(r>mid)
    {
        tret ret0=query(x*2+1,l,r);
        if(ret.mmin>ret0.mmin)
            ret.mmin=ret0.mmin,ret.num=ret0.num;
    }
    return ret;
}

struct tedge
{
    int a,b;
    int w;
};
tedge edge[maxn*4+10];
int cnt=1;

//加边
void addedge(int n)
{
    build(1,1,n);
    for(int i=n;i>=1;i--)
    {
        tret ret=query(1,dot[i].dis,n);
        if(ret.num!=0)
        {
            edge[cnt].a=dot[i].num;
            edge[cnt].b=ret.num;
            edge[cnt++].w=ret.mmin-dot[i].x-dot[i].y;
        }
        modify(1,dot[i].dis,dot[i].x+dot[i].y,dot[i].num);
    }
}

//kruskal用比较函数
int cmp(tedge a,tedge b)
{
    return a.w<b.w;
}

int fa[maxn+10];

int father(int x)
{
    if(fa[x]==x)
        return x;
    return fa[x]=father(fa[x]);
}

int main()
{
    int n,k;
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++)
    {
        scanf("%d%d",&dot[i].x,&dot[i].y);
        dot[i].num=i;
    }

    discrete(n);
    addedge(n);

    for(int i=1;i<=n;i++)
        swap(dot[i].x,dot[i].y);
    discrete(n);
    addedge(n);

    for(int i=1;i<=n;i++)
        dot[i].x*=-1;
    discrete(n);
    addedge(n);

    for(int i=1;i<=n;i++)
        swap(dot[i].x,dot[i].y);
    discrete(n);
    addedge(n);

    //kruskal
    for(int i=1;i<=n;i++)
        fa[i]=i;
    sort(edge+1,edge+cnt,cmp);
    for(int i=1,j=0;i<cnt;i++)
    {
        int fx=father(edge[i].a);
        int fy=father(edge[i].b);
        if(fx!=fy)
        {
            fa[fx]=fy;
            j++;
        }
        if(j==n-k)
        {
            printf("%d
",edge[i].w);
            break;
        }
    }

    return 0;
}
View Code

 

PS:看别人的解题报告只是一种学习的途径。代码的实现还是要靠自己写。这两者的深度是大不相同的,有些东西只有在自己写代码的时候才能体会到。这道题前前后后写了三遍,终于过了,开心。

以上是关于poj 3241 Object Clustering (曼哈顿最小生成树)的主要内容,如果未能解决你的问题,请参考以下文章

SQL2008 还原数据库 提示错误3241

前端学习(3241):react生命周期forceUpdate

JZOJ 3241. Money

P3241 [HNOI2015]开店

51nod 3241堆小明和他的同学们

BZOJ3241 [Noi2013]书法家/UOJ125