Another Minimum Spanning Tree - UVaLive 3662 曼哈顿最小生成树

本文详细介绍了如何使用曼哈顿距离构建最小生成树,并通过实例演示了求解过程。通过输入点集坐标,算法能高效计算出曼哈顿最小生成树的权重总和。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

For a given point set P = {(xiyi) : 1 $ \leq$ i $ \leq$ n}, then construct a complete graph G = (VEW) with nvertexes. The weight function for any two vertexes is w(vivj) = | xi - xj| + | yi - yj|. Please calculate the minimum spanning tree of G.

Hint 

For the graph below, there exists a minimum spanning tree in which there is at most one vertex connected withA in the shadow area. You can extend this property to solve the problem.

\epsfbox{p3662.eps}

Input 

Input contains several cases.

Each cases begins with an integer n$ \leq$ n $ \leq$ 100, 000, to indicate the size of the point set. The points in the point set have serial numbers from 1 to n.

Each line of the following n lines contains two non-negative integers (xiyi) (no more than 107) to describe the coordinate for each point. Any two points' coordinates are different.

The last case is followed by a line containing a zero.

Output 

For each case, output the case's serial number and the weighted sum of all minimum spanning tree edges in the following format.

Sample Input 

3
0 0
2 0
0 3
0

Sample Output 

Case 1: Total Weight = 5

题意:求曼哈顿最小生成树。

AC代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct node
{
    int x,y,pos;
}point[100010];
struct node2
{
    int u,v,w;
}edge[40000010];
int T,t,n,N=40000020,tot,p[100010],c[40000020],d[40000020],INF=1e9;
bool cmp(node a,node b)
{
    return a.x<b.x || (a.x==b.x && a.y<b.y);
}
bool cmp2(node2 a,node2 b)
{
    return a.w<b.w;
}
int lowbit(int x)
{
    return x&(-x);
}
int find(int x)
{
    return x==p[x] ? x : p[x]=find(p[x]);
}
void query(int val,int w,int pos)
{
    int id=-1,minn=INF,i;
    val+=20000010;
    for(i=val;i<N;i+=lowbit(i))
       if(c[i]<minn)
       {
           minn=c[i];
           id=d[i];
       }
    if(id!=-1)
    {
        tot++;
        edge[tot].u=pos;
        edge[tot].v=id;
        edge[tot].w=minn-w;
    }
}
void update(int val,int w,int pos)
{
    int i,j,k;
    val+=20000010;
    for(i=val;i>0;i-=lowbit(i))
       if(w<c[i])
       {
           c[i]=w;
           d[i]=pos;
       }
}
void go()
{
    int i,j,k;
    sort(point+1,point+1+n,cmp);
    for(i=1;i<N;i++)
       c[i]=INF;
    for(i=n;i>=1;i--)
    {
        query(point[i].y-point[i].x,point[i].y+point[i].x,point[i].pos);
        update(point[i].y-point[i].x,point[i].y+point[i].x,point[i].pos);
    }
}
ll work()
{
    int i,j,k,u,v;
    ll ans=0;
    tot=0;
    go();
    for(i=1;i<=n;i++)
       swap(point[i].x,point[i].y);
    go();
    for(i=1;i<=n;i++)
       point[i].y=-point[i].y;
    go();
    for(i=1;i<=n;i++)
       swap(point[i].x,point[i].y);
    go();
    sort(edge+1,edge+1+tot,cmp2);
    for(i=1;i<=n;i++)
       p[i]=i;
    for(i=1;i<=tot;i++)
    {
        u=find(edge[i].u);
        v=find(edge[i].v);
        if(u==v)
          continue;
        p[u]=v;
        ans+=edge[i].w;
    }
    return ans;
}
int main()
{
    int i,j,k;
    ll ans;
    while(~scanf("%d",&n) && n>0)
    {
        for(i=1;i<=n;i++)
        {
            scanf("%d%d",&point[i].x,&point[i].y);
            point[i].pos=i;
        }
        ans=work();
        printf("Case %d: Total Weight = %lld\n",++t,ans);
    }
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值