题目描述
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)条路分别连接了哪两个农场,他希望你计算一下,为了使得所有农场连通,他所需建造道路的最小总长是多少。
题目解析
先计算出点之间的距离,构造成邻接矩阵,对于已有的道路将距离变为0
求最小生成树即可。因为是稠密图,用 P r i m Prim Prim会比较好。
代码
#include<bits/stdc++.h>
#define N 1005
using namespace std;
int n,m;
int x[N],y[N];
bool vis[N];
double mat[N][N],dis[N],ans;
void prim()
{
for(int i=1;i<=n;i++) dis[i]=1e9;
dis[1]=0;
for(int i=1,u;i<n;i++)
{
u=0;
for(int j=1;j<=n;j++)
if(!vis[j]&&(u==0||dis[j]<dis[u])) u=j;
vis[u]=1;
for(int j=1;j<=n;j++)
if(!vis[j]) dis[j]=min(dis[j],mat[u][j]);
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=1000;i++) for(int j=1;j<=1000;j++) mat[i][j]=1e9;
for(int i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
for(int j=1;j<i;j++)
mat[i][j]=mat[j][i]=sqrt((double)(x[i]-x[j])*(x[i]-x[j])+(double)(y[i]-y[j])*(y[i]-y[j]));
}
for(int i=1,u,v;i<=m;i++)
scanf("%d%d",&u,&v),mat[u][v]=mat[v][u]=0;
prim();
for(int i=1;i<=n;i++) ans+=dis[i];
printf("%.2lf",ans);
}