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