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

好消息,为庆祝自己暑假上蓝,并成功晋级为参赛队员。我决定在这个暑假集训中写一篇研究性报告,像那些国家集训队的人那样,当然质量没有那么高。我假装网上没有直接完整的关于曼哈顿最小生成树资料。于是自己就想做整理和详细解释的工作。后文会放上自己参考的blog,喝水不忘挖井人。

摘    要:

曼哈顿最小生成树,是把最小生成树中两点直线距离的条件改成了在坐标系下的曼哈顿距离的条件。

结    论:

以一个点为原点建立直角坐标系,在每45度内只会向距离该点最近的一个点连边。

算法过程:

我直接就按照算法runing的顺序来解释了,总的来说,这个算法,第一步,在给定的点中,连出最有用的边,第二步就直接利用克鲁斯卡尔(Kruskal)算法,求出最小的费用。

建边时,每个点的45度就有八个区域,但是,由于这是一个无向图,所以只用考虑四个区域。我们假定x轴正半轴向上45’的区域为R1,逆时针为R2,R3,R4,R5,R6,R7,R8。第一次我们可以处理R2区域。第二次,通过交换每个点自己的x坐标和y坐标,R1和R2交换,R3和R8交换,这样,第一次对R2区域的操作,现在就是对R1的操作。第三次,我们把每个点的x坐标交换一下正负号,这样,第一次对R2区域的操作,现在就是对R8的操作。第四次,再次交换每个点的x坐标和y坐标,这样,第一次对R2区域的操作,现在就是对R7的操作。这样单边四个区域我们就枚举完了。

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;      ...}

下面我们来考虑,怎么处理第一个区域R2的信息。

我们每次处理R2区域的时候,在某个点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)。

我再说一下,就是,这里看的不是一个点,而是考虑每次在区间中加入一个点A,我们要给这个点找到距离它最近的满足条件的点B(就是点B 在点A的右上方,即B点的斜率大于A点的斜率,且距离A不能再近了),建立一条边。然后我们要把A的信息留在区间,留着给下一个点用,要留的信息就是A的x坐标与y坐标之和,因为,

|AB|=y1-y0+x1-x0=(x1+y1)-(x0+y0)。在A的区域内距离A最近的点也即满足条件的点中x+y最小的点。

for(int i = n; i >= 1; i--){
              int pos = query(a[i]);
        if(pos!=-1){
          addedge(p[i], p[pos]);
             }
         update(a[i], p[i].x + p[i].y, i);
}

这里的query和update我用的是树状数组,原来树状数组还可以怎么用,不是单点更新和区间求和。对于树状数组中的每一个点,完全可以向后得到后面传过来的信息,向前传去需要更新的信息。还很快,每次不需要O(n),只用O(logN).

建边完成之后,就可以直接用克鲁斯卡尔(Kruskal)算法了。

具体用途;

poj3241Object Clustering

http://poj.org/problem?id=3241

这个题目的意思是:

给定n个点,允许分成k块,在最优秀的分法中,最大的一条边(长度用曼哈顿距离表示)最小可以是多少。

这个题目可以转化成先建立一个最小生成树,去掉k-1条边之后,最大的边长度是多少。

注意这道题g++不可过,换成c++就过了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <list>
#include <cstdlib>
#include <iterator>
#include <cmath>
#include <iomanip>
#include <bitset>
#include <cctype>
using namespace std;
//#pragma GCC optimize(3)
//#pragma comment(linker, "/STACK:102400000,102400000")  //c++
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue

typedef long long ll;
typedef unsigned long long ull;

typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int ,pii> p3;
//priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl ‘\n‘

#define OKC ios::sync_with_stdio(false);cin.tie(0)
#define FT(A,B,C) for(int A=B;A <= C;++A)  //用来压行
#define REP(i , j , k)  for(int i = j ; i <  k ; ++i)
//priority_queue<int ,vector<int>, greater<int> >que;

const ll mos = 0x7FFFFFFFLL;  //2147483647
const ll nmos = 0x80000000LL;  //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3fLL; //18
const double PI=acos(-1.0);

template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) f|=(ch==‘-‘),ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x=f?-x:x;
}
// #define _DEBUG;         //*//
#ifdef _DEBUG
freopen("input", "r", stdin);
// freopen("output.txt", "w", stdout);
#endif
/*-----------------------show time----------------------*/

const int maxn = 1e5+9;
struct Point{
    int x,y,id;

    bool operator < (const Point &q)const{
        if(x == q.x)return y < q.y;
        return x < q.x;
    }
}p[maxn];

struct BITnode{
    int w,p;
}BITsum[maxn];

struct Edge{
    int u,v,dis;//曼哈顿距离
    bool operator < (const Edge & e)const {
        return dis < e.dis;
    }
} e[maxn << 3 | 1];

int tot = 0,fa[maxn];
int find(int x){
    if(fa[x] == x)return x;
    else return fa[x] = find(fa[x]);
}
void addedge(Point a,Point b){
    tot ++;
    e[tot].u = a.id;
    e[tot].v = b.id;
    e[tot].dis = abs(a.x - b.x) + abs(a.y-b.y);
}
int lowbit(int x){
    return x & (-x);
}
int a[maxn],n,k,*ix[maxn];
bool cmp(int * x,int * y){
    return (*x) < (*y);
}
int query(int x){
    int mx = inf,p = -1;
    while(x <= n){
        if(BITsum[x].w < mx){
            mx = BITsum[x].w;
            p = BITsum[x].p;
        }
        x += lowbit(x);
    }
    return p;
}

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

int main(){

    scanf("%d%d", &n, &k);

    for(int i = 1; i <= n; i++){
        scanf("%d%d", &p[i].x, &p[i].y);
        p[i].id = i;
    }
    // 建立边
    tot = 0;
    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] = p[i].y - p[i].x, ix[i] = &a[i];
        sort(ix + 1, ix + n + 1, cmp);

        for(int i=1; i<=n; i++) *ix[i] = i;
        for(int i = 1; i <= n; i++)
            BITsum[i].w = inf,BITsum[i].p = -1;

        for(int i = n; i >= 1; i--){
            int pos = query(a[i]);
            if(pos!=-1){
                addedge(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++)fa[i] = i;

    int cnt = n - k,c1 = 0,ans = 0;
    for(int i=1; i<= tot; i++){
        if( find(e[i].u) != find(e[i].v) ){
            int px = find(e[i].u);
            int py = find(e[i].v);
            fa[px] = py;
            c1++;
            if(c1 == cnt){ ans = e[i].dis;break;}
        }
    }
    printf("%d\n", ans);

    return 0;
}

POJ3241

参考:https://www.cnblogs.com/xzxl/p/7237246.html

https://blog.csdn.net/huzecong/article/details/8576908

https://blog.csdn.net/u013351484/article/details/47425981

原文地址:https://www.cnblogs.com/ckxkexing/p/9524298.html

时间: 2024-10-09 07:06:39

曼哈顿最小生成树 全网最全的相关文章

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

全网最全ASP.NET MVC 教程汇总

全网最全ASP.NET MVC 教程汇总 MVC架构已深得人心,微软也不甘落后,推出了Asp.net MVC.小编特意整理博客园乃至整个网络最具价值的MVC技术原创文章,为想要学习ASP.NET MVC技术的学习者提供一个整合学习入口.本文从Why,What,How三个角度整理MVC 的学习资源,让学习者第一时间找到最有价值的文章,获取最彻底的ASp.NET MVC 框架知识,Let’s go! 1. Why :为什么需要ASP.NET MVC 本章主要为大家汇总了为什么学习Asp.net MV

平面点曼哈顿最小生成树——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

自学MVC看这里——全网最全ASP.NET MVC 教程汇总(转)

自学MVC看这里——全网最全ASP.NET MVC 教程汇总 MVC架构已深得人心,微软也不甘落后,推出了Asp.net MVC.小编特意整理博客园乃至整个网络最具价值的MVC技术原创文章,为想要学习ASP.NET MVC技术的学习者提供一个整合学习入口.本文从Why,What,How三个角度整理MVC 的学习资源,让学习者第一时间找到最有价值的文章,获取最彻底的ASp.NET MVC 框架知识,Let’s go! 1. Why :为什么需要ASP.NET MVC 本章主要为大家汇总了为什么学习

【全网最全的博客美化系列教程】文章总目录

前言 很多热心的园友叫我出一部博客美化系列的教程,都觉得我博客做的很漂亮?之前我也有写过博客美化教程,不过好像一篇文章的篇幅有点过长了,为了方便园友的查看,我决定重新出一套博客美化教程,把原有的功能进行细化,每种功能单独以一篇文章的形式发表,在保留原有功能的基础上,会持续更新探索一些好玩好看的新功能,供园友们学习.既然是园友们提出的想法,我也不能辜负你们的期望啊,喜欢的园友记得点赞收藏加关注哦~~~ 一枚即将步入大三的学生党也是时候需要考虑一下自己的未来了,毕竟学习的时间不多了.我也很久没有更新

【全网最全的博客美化系列教程】05.公告栏个性时间显示的实现

全网最全的博客美化系列教程相关文章目录 [全网最全的博客美化系列教程]01.添加Github项目链接 [全网最全的博客美化系列教程]02.添加QQ交谈链接 [全网最全的博客美化系列教程]03.给博客添加一只萌萌哒的小仓鼠 [全网最全的博客美化系列教程]04.访客量统计的实现 [全网最全的博客美化系列教程]05.公告栏个性时间显示的实现 [全网最全的博客美化系列教程]06.推荐和反对炫酷样式的实现 [全网最全的博客美化系列教程]07.添加一个分享的按钮吧 [全网最全的博客美化系列教程]08.自定义

【全网最全的博客美化系列教程】06.推荐和反对炫酷样式的实现

全网最全的博客美化系列教程相关文章目录 [全网最全的博客美化系列教程]01.添加Github项目链接 [全网最全的博客美化系列教程]02.添加QQ交谈链接 [全网最全的博客美化系列教程]03.给博客添加一只萌萌哒的小仓鼠 [全网最全的博客美化系列教程]04.访客量统计的实现 [全网最全的博客美化系列教程]05.公告栏个性时间显示的实现 [全网最全的博客美化系列教程]06.推荐和反对炫酷样式的实现 [全网最全的博客美化系列教程]07.添加一个分享的按钮吧 [全网最全的博客美化系列教程]08.自定义

【全网最全的博客美化系列教程】07.添加一个分享的按钮吧

全网最全的博客美化系列教程相关文章目录 [全网最全的博客美化系列教程]01.添加Github项目链接 [全网最全的博客美化系列教程]02.添加QQ交谈链接 [全网最全的博客美化系列教程]03.给博客添加一只萌萌哒的小仓鼠 [全网最全的博客美化系列教程]04.访客量统计的实现 [全网最全的博客美化系列教程]05.公告栏个性时间显示的实现 [全网最全的博客美化系列教程]06.推荐和反对炫酷样式的实现 [全网最全的博客美化系列教程]07.添加一个分享的按钮吧 [全网最全的博客美化系列教程]08.自定义