uva 10397 Connect the Campus

最小生成树

和这道题是一样的,不过就是给出的数据不同hdu 1879 继续畅通工程

说来惭愧,写hdu那个的时候是1Y的,但是写这个却WA了一次是因为整个做法想错了

WA的想法是先用邻接矩阵建图,然后用一个had数组记录已经存在的边,在计算MST最小权值的时候如果是已有的边就不用算费用,所以需要adj数组去记录 边的信息

但是这个方法显然是错的,因为MST不是唯一的,如果最后MST的总权值最小,但是可能不同的MST用到的已有的边的条数是不同,用到的已有的边最少,那么需要额外付的费用就越好,如果是上面那样做,显然是WA

正确的做法就是把已有的边的权值赋值为0或者一个负数都可以(最好是0,那么就不用判断是否要并入花费中),因为这题是给出坐标,然后两点的距离就是权值,显然距离没有0或者负数的,因为题目说了不会有相同坐标的点。同样也不会有平行边,题目以说

然后就是prim算法或者kruskal算法都可以,直接模板就行了,因为已有的边权值为0,那么肯定会尽可能找到多的这些边的

所以其实adj数组使不需要的

这里给的是prim,kruskal就不给了

#include <cstdio>

#include <cstring>

#include <cmath>

#define INF 1000000000.000

#define N 800

double g[N][N],lowcost[N];

int x[N],y[N],cov[N];

int n,m;



double dis(int i , int j)

{  return sqrt(1.0*(x[i]-x[j])*(x[i]-x[j])+1.*(y[i]-y[j])*(y[i]-y[j]));  }

void input()

{

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

        scanf("%d%d",&x[i],&y[i]);

    for(int i=1; i<=n; i++) g[i][i]=INF;

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

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

            g[i][j]=g[j][i]=dis(i,j);

    scanf("%d",&m);

    for(int i=1; i<=m; i++)

    {

        int u,v;

        scanf("%d%d",&u,&v);

        g[u][v]=g[v][u]=0;

    }

}



void prim()

{

    

    double sum=0;

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

    { lowcost[i]=g[1][i]; cov[i]=0; }

    cov[1]=1; lowcost[1]=0;



    for(int nn=1; nn<n; nn++)

    {

        double min=INF;  int u=1;

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

            if(!cov[i] && lowcost[i]<min)

            { min=lowcost[i]; u=i; }

        cov[u]=1;

        sum+=lowcost[u];



        for(int v=1; v<=n; v++)

            if(!cov[v] && g[u][v]<lowcost[v])

                lowcost[v]=g[u][v];

    }



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

}

int main()

{

    while(scanf("%d",&n)!=EOF)

    {

        input();

        prim();

    }

    return 0;

}

 

你可能感兴趣的:(connect)