Description
Farmer John had just acquired several new farms! He wants to connect the farms with roads so that he can travel from any farm to any other farm via a sequence of roads; roads already connect some of the farms.
Each of the N (1 ≤ N ≤ 1,000) farms (conveniently numbered 1..N) is represented by a position (Xi,Yi) on the plane (0 ≤Xi ≤ 1,000,000; 0 ≤Yi ≤ 1,000,000). Given the preexistingM roads (1 ≤ M ≤ 1,000) as pairs of connected farms, help Farmer John determine the smallest length of additional roads he must build to connect all his farms.
Input
* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Two space-separated integers: Xi andYi
* Lines N+2..N+M+2: Two space-separated integers:
i and j, indicating that there is already a road connecting the farmi and farmj.
Output
* Line 1: Smallest length of additional roads required to connect all farms, printed without rounding to two decimal places. Be sure to calculate distances as 64-bit floating point numbers.
Sample Input
4 1 1 1 3 1 2 3 4 3 1 4
Sample Output
4.00
坐标类的最短路;
基础题。同时再总结一下Prim算法。
选取一个根节点,每次选取与树距离最短的一条路加入。
此题利用邻接矩阵。
在这总结一下最短路Prim与Kruskal的区别:
Prim适合于邻接矩阵,而Kruskal更适合于邻接表。
同时得出一个结论,Prim算法比较适合求稠密图的最小生成树,Kruskal算法比较适合求稀疏图的最小生成树。
在做题时要注意如何选择Prim与Kruskal。
当点少边多时,如1000个点500000条边时,这种变态数据,Prim就要开1000*1000的数组;
而Kruskal只需开一个500000数组。
当点多边少时如500000个点,1000条边,这主要是为了限制内存。Prim就绝对没戏,Kruskal就笑了。
同时,在满足空间的情况下,一般数据的Prim的时间是能完全碾压Kruskal的,大概在20倍左右。此时会有,在变态空间数据选择Kruskal时会超时,而Prim优化内存这不能搞,这时就得Kruskal优化时间了。即在普通Kruskal搜索选择最小边时,做文章,由于每次都得重复搜素最小边,不如一开始将其排序,改进后变为Kruskal+qsort,这时时间就能与Prim相差无几。事实上我们用kruskal一般都是先排序的。所以空间大的时候,和其他情况都可以用到kruskal。
#include <iostream> #include <cstdio> #include <cmath> #include <cstring> using namespace std; const int maxn=1002; const double maxm=2000000; bool visit[maxn]; int n; double sum; double x[maxn],y[maxn],lowcost[maxn],weight[maxn][maxn]; double dist(double x1,double y1,double x2,double y2) { return sqrt(pow(x2-x1,2)+pow(y2-y1,2)); } void Prim(int u) { int i,j,k; double min; for(i=1;i<=n;i++) if(i!=u) lowcost[i]=weight[1][i]; //lowcost取1节点到其他节点的距离。 visit[1]=true; for(i=1;i<n;i++) //注意!最小生成树有n-1条边 { min=maxm; for(j=1;j<=n;j++) if(lowcost[j]<min && !visit[j]) { min=lowcost[j]; k=j; //记录哪个点与当前最小生成树的距离最小 } sum+=min; visit[k]=true; for(j=1;j<=n;j++) //给在保留先前的路且在k上寻找较较小的路赋给lowcost if(lowcost[j]>weight[k][j] && !visit[j])//能是lowcost始终为树外最小的n条路。 lowcost[j]=weight[k][j]; } } int main() { int i,j,m,a,b; while(scanf("%d%d",&n,&m)!=EOF) { for(i=1;i<=n;i++) //农场从1开始标号 scanf("%lf%lf",&x[i],&y[i]); for(i=1;i<=n;i++) for(j=1;j<=n;j++) weight[i][j]=maxm; for(i=1;i<n;i++) //邻接矩阵 for(j=i+1;j<=n;j++) { weight[i][j]=dist(x[i],y[i],x[j],y[j]); weight[j][i]=weight[i][j]; } memset(visit,0,sizeof(visit)); for(i=1;i<=m;i++) { scanf("%d%d",&a,&b); //这些dist清为零 weight[a][b]=0; weight[b][a]=0; } sum=0; Prim(1); //以第一个结点为起点生成最小生成树 printf("%.2lf\n",sum); } return 0; }