51NOD 1213 二维曼哈顿距离最小生成树

来源:互联网 发布:linux 查看服务器配置 编辑:程序博客网 时间:2024/05/17 08:35

因为是二维平面图,所以点很多,如果全部点都连边,将有N*(N+1)/2条边,数组肯定存不下,所以要想办法减少边数。题目要求的是最小生成树的权值,又是曼哈顿距离,可以发现,对于平面上的某个点,以该点为原点建立直角坐标系,则我们只需要连接四个象限中每个象限离它最近的那个点即可,所以边的数量减少到4*N。
对于每个点,用树状数组维护每个象限离它的最近的那个点的权值就好了

#include <map>#include <set>#include <cmath>#include <ctime>#include <stack>#include <queue>#include <cstdio>#include <memory>#include <cctype>#include <bitset>#include <string>#include <vector>#include <climits>#include <cstring>#include <iostream>#include <iomanip>#include <algorithm>#include <functional>//#define FIN freopen("input.txt","r",stdin);//#define FOUT freopen("output.txt","w+",stdout);using namespace std;typedef long long ll;const int INF = 0x3f3f3f3f;const int mod = 1e9 + 7;const double eps=1e-8;const double Pi=acos(-1.0);const int N=50010;struct point{    int x,y,id;    bool operator<(const point p)const    {        return x!=p.x?x<p.x:y<p.y;    }} p[N];struct BIT{    int min_val,pos;    void init()    {        min_val=INF;        pos=-1;    }} bit[N];int par[N];//并查集中父亲int hight[N];//并查集树的高度struct edge{    int u,v,cost;};edge G[N<<2];//边集(边数)int V,E;//顶点数和边数int get_Manhadm_dis(point a,point b){    return abs(a.x-b.x)+abs(a.y-b.y);}void addedge(int u,int v,int w){    G[E].u=u;    G[E].v=v;    G[E++].cost=w;}int lowbit(int x){    return x&(-x);}void update(int x,int val,int pos){    for(int i=x; i>=1; i-=lowbit(i))        if(val<bit[i].min_val)        {            bit[i].min_val=val;            bit[i].pos=pos;        }}int ask(int x,int m){    int min_val=INF;    int pos=-1;    for(int i=x; i<=m; i+=lowbit(i))        if(bit[i].min_val<min_val)        {            min_val=bit[i].min_val;            pos=bit[i].pos;        }    return pos;}void make_edge(){    int a[N],b[N];    for(int dir=0; dir<4; dir++)    {        if(dir==1||dir==3)            for(int i=0; i<V; i++)                swap(p[i].x,p[i].y);        else if(dir==2)            for(int i=0; i<V; i++)                p[i].x=-p[i].x;        sort(p,p+V);        for(int i=0; i<V; i++)            a[i]=b[i]=p[i].y-p[i].x;        sort(b,b+V);        int m=unique(b,b+V)-b;        for(int i=1; i<=m; i++)            bit[i].init();        for(int i=V-1;i>=0; i--)        {            int pos=lower_bound(b,b+m,a[i])-b+1;            int ans=ask(pos,m);            if(ans!=-1)                addedge(p[i].id,p[ans].id,get_Manhadm_dis(p[i],p[ans]));            update(pos,p[i].x+p[i].y,i);        }    }}//并查集初始化void Init_union_find(int n){    for(int i=0; i<n; i++)    {        par[i]=i;        hight[i]=0;    }}//查询树的根int find(int x){    if(par[x]==x)        return x;    else        return par[x]=find(par[x]);}//合并x和y所属的集合void unite(int x,int y){    x=find(x);    y=find(y);    if(x==y)        return ;    if(hight[x]<hight[y])        par[x]=y;    else    {        par[y]=x;        if(hight[x]==hight[y])            hight[x]++;    }}//判断x和y是否属于同一个集合bool same(int x,int y){    return find(x)==find(y);}bool cmp(const edge& a,const edge& b){    return a.cost<b.cost;}int kruskal(){    sort(G,G+E,cmp);//按照edge.cost的顺序从小到大排列    Init_union_find(V);//并查集初始化    int ans=0;    for(int i=0; i<E; i++)    {        edge e=G[i];        if(!same(e.u,e.v))        {            unite(e.u,e.v);            ans+=e.cost;        }    }    return ans;}int main(){    scanf("%d",&V);    for(int i=0; i<V; i++)    {        scanf("%d %d",&p[i].x,&p[i].y);        p[i].id=i+1;    }    E=0;    make_edge();    printf("%d\n",kruskal());}
原创粉丝点击