公路修建

【问题描述】

       某国有n个城市,它们互相之间没有公路相通,因此交通十分不便。为解决这一“行路难”的问题,政府决定修建公路。修建公路的任务由各城市共同完成。

    修建工程分若干轮完成。在每一轮中,每个城市选择一个与它最近的城市,申请修建通往该城市的公路。政府负责审批这些申请以决定是否同意修建。

    政府审批的规则如下:

    (1)如果两个或以上城市申请修建同一条公路,则让它们共同修建;

(2)如果三个或以上的城市申请修建的公路成环。如下图,A申请修建公路AB,B申请修建公路BC,C申请修建公路CA。则政府将否决其中最短的一条公路的修建申请;

    (3)其他情况的申请一律同意。

    一轮修建结束后,可能会有若干城市可以通过公路直接或间接相连。这些可以互相:连通的城市即组成“城市联盟”。在下一轮修建中,每个“城市联盟”将被看作一个城市,发挥一个城市的作用。

    当所有城市被组合成一个“城市联盟”时,修建工程也就完成了。

    你的任务是根据城市的分布和前面讲到的规则,计算出将要修建的公路总长度。

【输入】

      第一行一个整数n,表示城市的数量。(n≤5000)

      以下n行,每行两个整数x和y,表示一个城市的坐标。(-1000000≤x,y≤1000000)

【输出】

      一个实数,四舍五入保留两位小数,表示公路总长。(保证有惟一解)

【样例】

       road.in                        road.out                      修建的公路如图所示:

       4                                 6.47

       0 0

       1 2

       -1 2

       0 4

【问题分析】

       三条规则中的第二条是故弄玄虚。如果三个或三个以上的城市申请修建的公路成环,那么这些公路的长度必然都相同,否则不满足“每个城市选择一个与它最近的城市,申请修建通往该城市的公路”。所以,如果成环,其实是任意去掉一条路。

 

#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm> 
#define M 5010
using namespace std;
int fa[M],n,cnt;
double x[M],y[M];
struct node
{
    int x,y;
    double v;
};node e[M*M];
double init(int i,int j)
{
    cnt++;
    e[cnt].x=i;
    e[cnt].y=j;
    e[cnt].v=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));
}
int cmp(const node&x,const node&y)
{
    return x.v<y.v;
}
int found(int x)
{
    if(fa[x]==x)return x;
    else return fa[x]=found(fa[x]);
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
      scanf("%lf%lf",&x[i],&y[i]),
      fa[i]=i;
    for(int i=1;i<n;i++)
      for(int j=i+1;j<=n;j++)
          init(i,j);
    sort(e+1,e+cnt+1,cmp);
    double ans=0;
    for(int i=1;i<=cnt;i++)
    {
        int a=found(e[i].x);
        int b=found(e[i].y);
        if(a!=b)
        {
            ans+=e[i].v;
            fa[a]=b;
        }
    }
    printf("%.2lf",ans);
    return 0;
}
View Code
原文地址:https://www.cnblogs.com/harden/p/5596827.html