zoukankan      html  css  js  c++  java
  • 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:看别人的解题报告只是一种学习的途径。代码的实现还是要靠自己写。这两者的深度是大不相同的,有些东西只有在自己写代码的时候才能体会到。这道题前前后后写了三遍,终于过了,开心。

  • 相关阅读:
    windows phone 7 开发工具合集
    Windows Phone中文开发资源集中营
    Windows Phone 7 输入法升起时,保持页面不被推起
    winXP控制面板TTS语音打不开卡顿SDK开发无法播放中文解决方法MFC调用代码
    c#winform不要通过文件右键属性去复制文件路径,会复制到隐藏的字符,打印路径会看见问号,导致无法打开指定文件
    密钥读yao还是yue?
    office access accdb驱动目录注册表路径
    c#winform判断是否为数字型字符串
    c#序列化json文件为字符串更改json对象内容
    在C#HttpWebRequest 设置超时方法
  • 原文地址:https://www.cnblogs.com/acboyty/p/9643799.html
Copyright © 2011-2022 走看看