poj3625 最小生成树 Prim

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;
}



 

 

posted @ 2012-12-04 11:23  amourjun  阅读(190)  评论(0编辑  收藏  举报