EOJ2067 最小生成树 prime算法+kruskal算法

来源:互联网 发布:软件广告好烦 编辑:程序博客网 时间:2024/05/24 01:52

EOJ2067 最小生成树 prime算法和kruskal算法实现


Description

Farmer John had just acquired several new farms! He wants to connect the farmswith roads so that he can travel from any farm to any other farm via a sequenceof roads; roads already connect some of the farms.

Each of the N (1 <= N <= 1,000) farms (conveniently numbered 1..N) isrepresented by a position (X_i, Y_i) on the plane (0 <= X_i <=1,000,000;0 <= Y_i <= 1,000,000). Given the preexisting M 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 allhis farms.

Input

* Line 1: Two space-separated integers: N and M
* Lines 2..N+1: Two space-separated integers: X_i and Y_i
* Lines N+2..N+M+2: Two space-separated integers: i and j, indicating thatthere is already a road connecting the farm i and farm j.

Output

4 1
1 1
3 1
2 3
4 3
1 4

INPUT DETAILS:
Four farms at locations (1,1), (3,1), (2,3), and (4,3). Farms 1 and 4 areconnected by a road.

Sample Input

* Line 1: Smallest length of additional roads required to connect allfarms,printed without rounding to two decimal places. Be sure to calculate distancesas 64-bit floating point numbers.

Sample Output

4.00

OUTPUT DETAILS:
Connect farms 1 and 2 with a road that is 2.00 units long, then connect farms 3and 4 with a road that is 2.00 units long. This is the best we can do, andgives us a total of 4.00 unit lengths.

题目分析:

给定一些点的坐标,要在这些点间修路,一些点间的路已经修好,求最短的修路长度,使得图连通,最小生成树练习题。先预处理出所有点间的距离,然后把已经修好的点间的距离改成0。接下来可用prime算法和kruskal算法实现。1.prime算法思路类似dijkstra算法,每次选择到正在构建的生成树距离最短的点加入树的构建中,并通过新加入的点更新此集合与集合外各点的最小距离。2.kruskal算法每次取最短边来建树,且不能出现回路。

比较两个算法发现prime算法效率较高,因为当图接近完全图时,kruskal的复杂图比prime算法多了一个log(n*n)的常数。

两种实现代码如下:

1.      prime算法:

#include <iostream>

#include <cstdio>

#include <cstring>

#include <cmath>

 

using namespace std;

struct Node{

    double x,y;

}node[1005];

 

double cost[1005][1005];

double low[1005];

bool vis[1005];

 

double dis(Node a,Node b){

    returnsqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));

}

 

double prime(int n){

    int i,j,k;

    double ans=0.0;

    vis[1]=true;

    for(i=2;i<=n;++i)

        low[i]=cost[1][i];

    for(i=1;i<=n-1;++i){

        double minn=1000000000;

        for(j=1;j<=n;++j){

            if(!vis[j] &&minn>low[j]){

                minn=low[j];k=j;

            }

        }

        vis[k]=true;

        ans+=low[k];

        for(j=1;j<=n;++j){

            if(!vis[j]){

                low[j]=min(low[j],cost[k][j]);

            }

        }

    }

    return ans;

}

 

int main()

{

    int n,m,i,j;

   memset(vis,false,sizeof(vis));

   scanf("%d%d",&n,&m);

    for(i=1;i<=n;++i)

       scanf("%lf%lf",&node[i].x,&node[i].y);

    for(i=1;i<=n;++i){

        for(j=i+1;j<=n;++j){

           cost[j][i]=cost[i][j]=dis(node[i],node[j]);

        }

    }

    for(i=0;i<m;++i)

    {

        int x,y;

       scanf("%d%d",&x,&y);

       cost[x][y]=cost[y][x]=0.0;

    }

    double ans=prime(n);

    printf("%.2f\n",ans);

    return 0;

}

 

2.      kruscal算法:

 

#include <iostream>

#include <cstdio>

#include <cmath>

#include <algorithm>

 

using namespace std;

struct Node{

    double x,y;

}node[1005];

 

struct E{

    int pt1,pt2;

    double length;

}e[1005*1005/2];

 

int set[1005];

 

int find(int x){

    returnx==set[x]?x:(set[x]=find(set[x]));

}

 

double dis(Node a,Node b){

    return(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);

}

 

bool cmp(const E& a,const E& b){

    return a.length<b.length;

}

 

double kruskal(int n,int k){

    double ans=0.0;

    int cnt=0,i;

    for(i=0;i<k;++i){

        intfx=find(e[i].pt1),fy=find(e[i].pt2);

        if(fx==fy) continue;

        set[fx]=fy;

        ans+=sqrt(e[i].length);

        ++cnt;

        if(cnt==n-1) break;

    }

    return ans;

}

 

int main()

{

    int n,m,i,j,k=0;

   scanf("%d%d",&n,&m);

    for(i=1;i<=n;++i)

       scanf("%lf%lf",&node[i].x,&node[i].y);

    for(i=1;i<=n;++i){

        for(j=1;j<=i-1;++j){

            e[k].pt1=i;

            e[k].pt2=j;

            e[k++].length=dis(node[i],node[j]);

        }

    }

    for(i=0;i<m;++i)

    {

        int x,y;

       scanf("%d%d",&x,&y);

        if(x<y) swap(x,y);

//       cout<<(x-2)*(x-1)/2+y-1<<endl;

       e[(x-2)*(x-1)/2+y-1].length=0.0;

    }

    sort(e,e+k,cmp);

    for(i=1;i<1005;++i)set[i]=i;

    double ans=kruskal(n,k);

   printf("%.2f\n",ans);

    return 0;

}

1 0