zoukankan      html  css  js  c++  java
  • POJ3241 最小曼哈顿距离生成树

    (有任何问题欢迎留言或私聊 && 欢迎交流讨论哦

    Catalog

    Problem:Portal传送门

     原题目描述在最下面。
     给你n个坐标,求最小曼哈顿距离生成树。

    Solution:

    请一定要理解:
     有一个剪枝:把坐标分成(8)块,在一个(45)度区间内,只需要向与之距离最近的点连边。
     虽然一共有(8)个相对区域,但我们只需考虑(4)个,中心对称的不需要再连一次边。这(4)个区域坐标转化一下即可求解。
     先考虑每个点(y)轴向右的(45)度区域,例如,对于(A)((x0,y0))(B(x1,y1))(A)点的那部分区域内。有(x0leq x1,; y0-x0leq y1-x1)。而(A)只要向满足此条件的大于(y0-x0)的最小(x+y)点连边。
     先把所有点按(x,y)坐标排序,从最后一个点往前处理(这样保证了(x1>x0)的问题),然后用树状数组维护最小的(x+y)


     再来思考坐标转化的问题,把[45,90]标记为1,[0,45]标记为2,[-45,0]标记为3,[-90,-45]标记为4.
     从区域1到2,3到4只需要交换x,y坐标即可;从区域2到3只需要把x坐标去相反数即可。

    AC_Code:

    #include<bits/stdc++.h>
    #define lson rt<<1
    #define rson rt<<1|1
    #define all(x) (x).begin(),(x).end()
    #define mme(a,b) memset((a),(b),sizeof((a)))
    #define fuck(x) cout<<"* "<<x<<"
    "
    #define iis std::ios::sync_with_stdio(false)
    using namespace std;
    typedef long long LL;
    typedef pair<int,int> pii;
    const int MXN = 1e5 + 7;
    const int MXE = 1e6 + 7;
    const int INF = 0x3f3f3f3f;
    int n, k, tot;
    int ar[MXN], fa[MXN];
    struct lp{
        int x, y, id;
    }cw[MXN], edge[MXE];
    bool cmp(const lp &a, const lp &b){
        if(a.x != b.x)return a.x < b.x;
        return a.y < b.y;
    }
    bool cmp1(const lp &a, const lp &b){
        return a.id < b.id;
    }
    //树状数组部分
    struct BIT{
        int w, p;
    }bit[MXN];
    int lowbit(int x){
        return x&(-x);
    }
    void add(int x, int w, int p){
        for(; x > 0; x -= lowbit(x)){
            if(bit[x].w > w)bit[x].w = w, bit[x].p = p;
        }
    }
    int query(int x){
        int mmax = INF, p = -1;
        for(; x <= n; x += lowbit(x)){
            if(bit[x].w < mmax)mmax = bit[x].w, p = bit[x].p;
        }
        return p;
    }
    int Fi(int x){
        return fa[x] == x? x: fa[x] = Fi(fa[x]);
    }
    void add_edge(int u,int v,int w){
        edge[++tot].x = u;edge[tot].y = v;edge[tot].id = w;
    }
    int abd(int x){return (x < 0)? -x : x;}
    int dist(int i, int j){
        return abs(cw[i].x-cw[j].x)+abs(cw[i].y-cw[j].y);
    }
    void kruskal(){
        sort(edge, edge + tot + 1, cmp1);
        int cnt = n - k, ans;
        for(int i = 0; i <= n; ++i)fa[i] = i;
        for(int i = 0; i <= tot && cnt; ++i){
            int pa = Fi(edge[i].x), pb = Fi(edge[i].y);
            if(pa == pb)continue;
            --cnt;
            ans = edge[i].id;
            fa[pb] = pa;
        }
        printf("%d
    ", ans);
    }
    /*
    我们只需考虑在一块区域内的点,其他区域内的点可以通过坐标变换“移动”到这个区域内。为了方
    便处理,我们考虑在y轴向右45度的区域。在某个点A(x0,y0)的这个区域内的点B(x1,y1)满足
    x1≥x0且y1-x1>y0-x0。这里对于边界我们只取一边,但是操作中两边都取也无所谓。那么
    |AB|=y1-y0+x1-x0=(x1+y1)-(x0+y0)。在A的区域内距离A最近的点也即满足条件的点中
    x+y最小的点。因此我们可以将所有点按x坐标排序,再按y-x离散,用线段树或者树状数组维护
    大于当前点的y-x的(最小的x+y)对应的点。时间复杂度O(NlogN)。
    */
    int main(int argc, char const *argv[]){
    #ifndef ONLINE_JUDGE
        freopen("E://ADpan//in.in", "r", stdin);
        //freopen("E://ADpan//out.out", "w", stdout);  
    #endif
        while(~scanf("%d%d", &n, &k)){
            tot = -1;
            for(int i = 0 ; i < n; ++i){
                scanf("%d%d", &cw[i].x, &cw[i].y);
                cw[i].id = i;
            }
            for(int dir = 1; dir <= 4; ++dir){
                //坐标转换
                if(dir % 2 == 0){
                    for(int i = 0; i < n; ++i)swap(cw[i].x, cw[i].y);
                }else if(dir == 3){
                    for(int i = 0; i < n; ++i)cw[i].x = -cw[i].x;
                }
                //先x再y排序
                sort(cw, cw +n, cmp);
                //Discretize
                for(int i = 0; i <= n; ++i){
                    ar[i] = cw[i].y - cw[i].x;
                    bit[i].w = INF; bit[i].p = -1;
                }
                sort(ar, ar + n);
                int k = unique(ar, ar + n) - ar;
                for(int i = n - 1; i >= 0; --i){
                    //按y-x编号
                    int p = lower_bound(ar, ar + k, cw[i].y - cw[i].x) - ar + 1;
                    int pos  = query(p);//获取最小的y+x
                    if(pos != -1){
                        add_edge(cw[i].id, cw[pos].id, dist(i, pos));
                    }
                    //添加y+x
                    add(p, cw[i].y + cw[i].x, i);
                }
            }
            kruskal();
        }
        return 0;
    }
    

    Problem Description:

    这里写图片描述

  • 相关阅读:
    Netty 心跳处理
    Netty 搭建 WebSocket 服务端
    Spring Boot 集成 MQTT
    Spring Boot 上传文件
    在 CentOS 7 安装 Tomcat
    神坑之 6666 端口 (默认非安全端口)
    MongoTemplate 移除 _class 字段
    在 CentOS 7 安装 RabbitMQ
    MongoDB 分片集群配置
    tensorflow学习(一)
  • 原文地址:https://www.cnblogs.com/Cwolf9/p/9622916.html
Copyright © 2011-2022 走看看