最小生成树-BZOJ-1626-[Usaco2007 Dec]Building Roads 修建道路

Description

Farmer John最近得到了一些新的农场,他想新修一些道路使得他的所有农场可以经过原有的或是新修的道路互达(也就是说,从任一个农场都可以经过一些首尾相连道路到达剩下的所有农场)。有些农场之间原本就有道路相连。 所有N(1 <= N <= 1,000)个农场(用1..N顺次编号)在地图上都表示为坐标为(X_i, Y_i)的点(0 <= X_i <= 1,000,000;0 <= Y_i <= 1,000,000),两个农场间道路的长度自然就是代表它们的点之间的距离。现在Farmer John也告诉了你农场间原有的M(1 <= M <= 1,000)条路分别连接了哪两个农场,他希望你计算一下,为了使得所有农场连通,他所需建造道路的最小总长是多少。
Input

  • 第1行: 2个用空格隔开的整数:N 和 M

    • 第2..N+1行: 第i+1行为2个用空格隔开的整数:X_i、Y_i * 第N+2..N+M+2行: 每行用2个以空格隔开的整数i、j描述了一条已有的道路, 这条道路连接了农场i和农场j

Output

  • 第1行: 输出使所有农场连通所需建设道路的最小总长,保留2位小数,不必做 任何额外的取整操作。为了避免精度误差,计算农场间距离及答案时 请使用64位实型变量

Sample Input
4 1

1 1

3 1

2 3

4 3

1 4

输入说明:

FJ一共有4个坐标分别为(1,1),(3,1),(2,3),(4,3)的农场。农场1和农场

4之间原本就有道路相连。

Sample Output
4.00

输出说明:

FJ选择在农场1和农场2间建一条长度为2.00的道路,在农场3和农场4间建一

条长度为2.00的道路。这样,所建道路的总长为4.00,并且这是所有方案中道路

总长最小的一种。

题解:
先算出两两间的距离,然后再让已有边距离置0,再跑最小生成树就行了。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <string>
#include <queue>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
const int MAXN=1005;
int n,m;
typedef struct node
{
    long long int x,y;
} node;
typedef struct edge
{
    int u,v;
} edge;
const double INF=1000000005;
edge Edge[1005];
node Node[1005];
double dis[1005][1005];
inline double distans(node a,node b)
{
    return sqrt((double)(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}
bool vis[MAXN];
double lowc[MAXN];
double Prim(double cost[][MAXN],int n)//点是0~n-1
{
    double ans=0;
    memset(vis,false,sizeof(vis));
    vis[0]=true;
    for(int i=1; i<n; i++)lowc[i]=cost[0][i];
    for(int i=1; i<n; i++)
    {
        double minc=INF;
        int p=-1;
        for(int j=0; j<n; j++)
            if(!vis[j]&&minc>lowc[j])
            {
                minc=lowc[j];
                p=j;
            }
        if(minc==INF)return -1;//原图不连通
        ans+=minc;
        vis[p]=true;
        for(int j=0; j<n; j++)
            if(!vis[j]&&lowc[j]>cost[p][j])
                lowc[j]=cost[p][j];
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    for(int i=0; i<n; i++)
        scanf("%lld%lld",&Node[i].x,&Node[i].y);
    for(int i=0; i<m; i++)
        scanf("%d%d",&Edge[i].u,&Edge[i].v);
    for(int i=0; i<n; i++)
    {
        for(int j=0; j<n; j++)
            dis[i][j]=INF;
        dis[i][i]=0;
    }
    for(int i=0; i<n; i++)
        for(int j=i+1; j<n; j++)
            dis[i][j]=dis[j][i]=distans(Node[i],Node[j]);
    for(int i=0; i<m; i++)
        dis[Edge[i].u-1][Edge[i].v-1]=dis[Edge[i].v-1][Edge[i].u-1]=0;
    printf("%.2f\n",Prim(dis,n));
    return 0;
}

你可能感兴趣的:(最小生成树,ACM)