链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=1203
题意:给出n个城市的坐标,计算连接这n个城市所需路线总长度的最小值。
思路:先求出每两个城市间的距离,也就是边权,然后用kruscal来求最小生成树,得出最小值。
注意输出格式,要求每两个输出之间要有一个空行。但是最后的一个输出后面不能有空行,所以判断是不是第一个输出,不是的话,先打一个空行。
一开始写wa了,找了很久错误没找出来,后面发现是cmp()函数写的有问题。
一开始我是直接把上次写的kruscal()示例程序中的cmp()函数粘贴了过来。没想问题,结果,呵呵。
好吧,这种比较函数我确实不是很懂,虽然也写过很多次。。。
#include<iostream> #include<cstdio> #include<cstring> #include<queue> #include<string> #include<cmath> #include<map> #include<algorithm> using namespace std; const int maxn=100; const int maxm=5000; int n,m; double sumw; double X[maxn],Y[maxn]; struct Edge { int u,v; double w; }edges[maxm]; class set { public: void makeset(int k) { for(int i=0; i<k; i++) { father[i]=i; rank[i]=1; } } int findset(int x) { if(x!=father[x]) father[x]=findset(father[x]); return father[x]; } void unionset(int x,int y) { x=findset(x); y=findset(y); if(x==y) return; if(rank[x]>rank[y]) { father[y]=x; rank[x]+=rank[y]; } else { father[x]=y; rank[y]+=rank[x]; } } private: int father[maxn]; int rank[maxn]; }ufs; int cmp(const void* a,const void* b) { Edge aa=*(const Edge*)a, bb=*(const Edge*)b; if(aa.w>bb.w) return 1; else return -1; // return aa.w-bb.w; } void kruscal() { int num=0,u,v; sumw=0.0; ufs.makeset(n); for(int i=0;i<m;i++) { u=edges[i].u;v=edges[i].v; if(ufs.findset(u)!=ufs.findset(v)) { num++; sumw+=edges[i].w; ufs.unionset(u,v); } if(num>=n-1) break; } } int main() { int kase=1; double d; while(scanf("%d",&n) && n) { for(int i=0;i<n;i++) scanf("%lf%lf",&X[i],&Y[i]); int mi=0;//边的序号 for(int i=0;i<n;i++) for(int j=i+1;j<n;j++) { d=sqrt((X[i]-X[j])*(X[i]-X[j])+(Y[i]-Y[j])*(Y[i]-Y[j])); edges[mi].u=i;edges[mi].v=j;edges[mi].w=d; mi++; } m=mi; qsort(edges,m,sizeof(edges[0]),cmp); kruscal(); if(kase>1) printf("\n"); printf("Case #%d:\n",kase++); printf("The minimal distance is: %.2lf\n",sumw); } return 0; }
究竟是我抛弃了历史,还是历史遗弃了我。