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

 

posted @ 2012-12-08 00:17  Titanium  阅读(401)  评论(0编辑  收藏  举报