[BZOJ2177][最小/最大(曼哈顿距离)生成树]曼哈顿最小生成树

来源:互联网 发布:全国书画艺术网络大赛 编辑:程序博客网 时间:2024/04/30 22:24

题意


给定平面内一些点,求最小曼哈顿距离生成树


看这篇咯http://blog.csdn.net/acm_cxlove/article/details/8890003

#include <cstdio>#include <string>#include <cstring>#include <iostream>#include <algorithm>#define N 100010#define X first#define Y secondusing namespace std;typedef long long ll;int n,m,cnt,cnt0;int B[N],C[N],D[N],fa[N];ll Ans;struct Point{    int x,y,id;}A[N];struct edge{    int u,v,w;    edge(int u=0,int v=0):u(u),v(v){}    friend bool operator <(edge a,edge b){        return a.w<b.w;    }}E[N<<3];inline bool cmpx(Point a,Point b){    return a.x<b.x;}inline bool cmpy(Point a,Point b){    return a.y<b.y;}inline bool back(Point a,Point b){    return a.id<b.id;}inline void reaD(int &x){    char c=getchar(); x=0; int f=1;    for(;c>'9'||c<'0';c=getchar())if(c=='-') f=-1;    for(;c>='0'&&c<='9';x=x*10+c-'0',c=getchar()); x*=f;}inline int query(int x){    int Min=1<<30,r=-1;    for(;x<=cnt;x+=x&-x)        if(C[x]<Min) Min=C[x],r=D[x];    return r;}inline void Add(int x,int y,int z){    for(;x;x-=x&-x)        if(y<C[x]) C[x]=y,D[x]=z;}int find(int x){    return fa[x]==x?x:fa[x]=find(fa[x]);}int main(){    reaD(n);    for(int i=1;i<=n;i++)        reaD(A[i].x),reaD(A[i].y),A[i].id=i;    for(int i=1;i<=n;i++) B[i]=A[i].y-A[i].x;    //1    sort(A+1,A+1+n,cmpx);    sort(B+1,B+1+n); cnt=unique(B+1,B+1+n)-B-1;    memset(C,0x7f,sizeof(C)); memset(D,-1,sizeof(D));    for(int i=n;i;i--){        int x=lower_bound(B+1,B+1+cnt,A[i].y-A[i].x)-B,pos=query(x);        if(pos>0) E[++cnt0]=edge(A[i].id,pos);        Add(x,A[i].x+A[i].y,A[i].id);    }    //4    memset(C,0x7f,sizeof(C)); memset(D,-1,sizeof(D));    for(int i=1;i<=n;i++) B[i]=-A[i].x-A[i].y;    sort(B+1,B+1+n); cnt=unique(B+1,B+1+n)-B-1;    for(int i=n;i;i--){        int x=lower_bound(B+1,B+1+cnt,-A[i].x-A[i].y)-B,pos=query(x);        if(pos>0) E[++cnt0]=edge(A[i].id,pos);        Add(x,A[i].x-A[i].y,A[i].id);    }    //2    sort(A+1,A+1+n,cmpy);    memset(C,0x7f,sizeof(C)); memset(D,-1,sizeof(D));    for(int i=1;i<=n;i++) B[i]=A[i].x-A[i].y;    sort(B+1,B+1+n); cnt=unique(B+1,B+1+n)-B-1;    for(int i=n;i;i--){        int x=lower_bound(B+1,B+1+cnt,A[i].x-A[i].y)-B,pos=query(x);        if(pos>0) E[++cnt0]=edge(A[i].id,pos);        Add(x,A[i].x+A[i].y,A[i].id);    }    //3    memset(C,0x7f,sizeof(C)); memset(D,-1,sizeof(D));    for(int i=1;i<=n;i++) B[i]=A[i].y+A[i].x;    sort(B+1,B+1+n); cnt=unique(B+1,B+1+n)-B-1;    for(int i=1;i<=n;i++){        //printf("%d\n",i);        int x=lower_bound(B+1,B+1+cnt,A[i].y+A[i].x)-B,pos=query(x);        if(pos>0) E[++cnt0]=edge(A[i].id,pos);        Add(x,A[i].x-A[i].y,A[i].id);    }    //mst    sort(A+1,A+1+n,back);    for(int i=1;i<=cnt0;i++)        E[i].w=abs(A[E[i].u].x-A[E[i].v].x)+abs(A[E[i].u].y-A[E[i].v].y);    sort(E+1,E+1+cnt0);    //for(int i=1;i<=cnt0;i++) printf("%d %d %d\n",E[i].u,E[i].v,E[i].w);    for(int i=1;i<=n;i++) fa[i]=i;    for(int i=1;i<=cnt0;i++){        if(find(E[i].u)==find(E[i].v)) continue;        fa[find(E[i].u)]=find(E[i].v);        Ans+=E[i].w;    }    cout<<Ans<<endl;    return 0;}

另外还有求最大曼哈顿距离生成树,好像有个叫Boruvka的算法
就是每次找到图中独立的一个团,找到一条最长的一个端点在这个团中另一个端点属于另一个团的边,把这两个端点属于的团合并,记录答案。

#include <cstdio>#include <cstring>#include <string>#include <iostream>#include <algorithm>#include <vector>#include <set>#define N 100010#define X first#define Y secondusing namespace std;typedef long long ll;typedef pair<int,int> paris;typedef pair<ll,paris> parpar;typedef set<paris>::iterator itr;int n;int fa[N],vis[N];int val[N][4];paris p[N];ll Ans;set<paris> S[4];vector<parpar> A;vector<int> V[N];int dx[4]={1,1,-1,-1},dy[4]={1,-1,-1,1};inline void reaD(int &x){    char c=getchar();x=0; int f=1;    for(;c>'9'||c<'0';c=getchar())if(c=='-')f=-1;    for(;c>='0'&&c<='9';x=x*10+c-'0',c=getchar()); x*=f;}int find(int x){ return fa[x]==x?x:fa[x]=find(fa[x]); }inline bool iUnion(int x,int y){    x=find(x); y=find(y);    if(x==y) return 0;    if(V[x].size()>V[y].size()) swap(x,y);    for(int i=0;i<V[x].size();i++)        V[y].push_back(V[x][i]);    V[x].clear();    fa[x]=y;    return 123;}int main(){    freopen("mst.in","r",stdin);    freopen("mst.out","w",stdout);    reaD(n);    for(int i=1;i<=n;i++)        reaD(p[i].X),reaD(p[i].Y);    for(int i=1;i<=n;i++){        fa[i]=i,V[i].push_back(i);        for(int j=0;j<4;j++){            val[i][j]=p[i].X*dx[j]+p[i].Y*dy[j];            S[j].insert(paris(val[i][j],i));        }    }    int linked=0;    while(!linked){        memset(vis,0,sizeof(vis));        for(int i=1;i<=n;i++){            int x=find(i);            if(vis[x]) continue;            if(V[x].size()==n){ linked=1; break; }            vis[x]=1;            for(int j=0;j<V[x].size();j++){                int u=V[x][j];                for(int k=0;k<4;k++)                    S[k].erase(paris(val[u][k],u));            }            int v; ll Max=-1;            for(int j=0;j<V[x].size();j++){                int u=V[x][j];                for(int k=0;k<4;k++){                    itr it=S[(k+2)%4].end(); it--;                    if(1ll*it->X+val[u][k]>Max) Max=1ll*it->X+val[u][k],v=it->Y;                }            }            A.push_back(parpar(Max,paris(x,v)));            for(int j=0;j<V[x].size();j++){                int u=V[x][j];                for(int k=0;k<4;k++)                    S[k].insert(paris(val[u][k],u));            }        }        for(int i=0;i<A.size();i++){            int u=A[i].Y.X,v=A[i].Y.Y; ll w=A[i].X;            if(iUnion(u,v)) Ans+=w;        }    }    cout<<Ans<<endl;    return 0;}
0 0
原创粉丝点击