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,并且这是所有方案中道路总长最小的一种。
HINT
Source
Silver
题解
简单朴素的prim算法,具体过程请点这里
代码
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
const int inf=1000000000;
double dist[1009][1009];
double low[1009];
int x[1009],y[1009],tr[1009];
int n,m,i,j,ans,xx,yy,mini;
double sum,minn;
double sqr(int a)
{
return 1.0*a*a;
}
void makedist()//计算距离
{
for (i=1;i<=n;i++)
{
for (j=1;j<=n;j++)
{
dist[i][j]=sqrt(sqr(x[i]-x[j])+sqr(y[i]-y[j]));
}
}
}
int prim()//prim算法
{
tr[1]=1;
for (i=1;i<=n;i++)
{
low[i]=inf;
}
for (i=2;i<=n;i++)
{
low[i]=dist[1][i];
}
mini=1;
sum=0;
for (i=1;i<=n-1;i++)
{
minn=inf;
for (j=1;j<=n;j++)
{
if ((low[j]<minn)&&(tr[j]==0))
{
minn=low[j];
mini=j;
}
}
tr[mini]=1;
sum+=minn;
for (j=1;j<=n;j++)
{
if ((tr[j]==0)&&(low[j]>dist[mini][j]))
{
low[j]=dist[mini][j];
}
}
}
printf("%.2lf",sum);
return 0;
}
int main()
{
scanf("%d%d",&n,&m);
for (i=1;i<=n;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
makedist();
for (i=1;i<=m;i++)
{
scanf("%d%d",&xx,&yy);
dist[xx][yy]=dist[yy][xx]=0;
}
ans=prim();
return 0;
}