本题其实就是求最小生成树,可以利用克鲁斯卡尔算法来解决。但是这里的边需要先处理出来,即把符合条件的边加入边集合中,这样就可以使用克鲁斯卡尔算法求解:排序+并查集检测连通性,最后得出结论。这里处理边的权重的时候没有直接处理double类型的数据,因为处理浮点型的数据有时候比较大小容易出错,而是保存的未开平方之前的int值,由题目数据可知这个值在100-1000000之间,所以保存起来排序也是比较方便的。
2 2 10 10 20 20 3 1 1 2 2 1000 1000
1414.2 oh!
#include <cstdio> #include <cstdlib> #include <cmath> const int MAX = 105; const int L = 100; const int R = 1000000; int cnt; double total; typedef struct{ int x,y; int cost; }Point; Point pot[MAX*MAX];//起初数组开小了,一直WA了三次,后来才想起边集数量最大可达到n*(n-1)/2 int pre[MAX],px[MAX],py[MAX]; int cal_len(int n){ int i,j,tx,ty,len,pos; pos = 0; for(i=0;i<n;++i){ for(j=i+1;j<n;++j){ tx = px[i]-px[j]; tx *= tx; ty = py[i]-py[j]; ty *= ty; len = tx + ty; if(len>=L && len<=R){ pot[pos].x = i; pot[pos].y = j; pot[pos].cost = len; ++pos; } } } return pos; } void init(int n){ int i; cnt = n-1; total = 0.0; for(i=0;i<n;++i){ pre[i] = i; } } int root(int x){ if(x!=pre[x]){ pre[x] = root(pre[x]); } return pre[x]; } int merge(int x,int y){ int ret = 0; int fx = root(x); int fy = root(y); if(fx!=fy){ --cnt; pre[fx] = fy; ret = 1; } return ret; } int cmp(const void *a,const void *b){ Point *pa = (Point *)a; Point *pb = (Point *)b; return pa->cost-pb->cost; } int main(){ int i,t,n; //freopen("in.txt","r",stdin); scanf("%d",&t); while(t--){ scanf("%d",&n); init(n); for(i=0;i<n;++i){ scanf("%d %d",&px[i],&py[i]); } int ln = cal_len(n); if(ln<n-1){ printf("oh!\n"); continue; } // printf("%d******\n",ln); qsort(pot,ln,sizeof(Point),cmp); for(i=0;i<ln;++i){ if(merge(pot[i].x,pot[i].y)==1){ total += sqrt(pot[i].cost*1.0); } } if(cnt!=0){ printf("oh!\n"); continue; }else{ printf("%0.1lf\n",total*100); continue; } } return 0; }