Description
Input
Output
Sample Input
2 2 10 10 20 20 3 1 1 2 2 1000 1000
Sample Output
1414.2 oh!
这题一开始RE了,原因是数组开小了。
题目大概意思是说 给出每个点的坐标(x,y)求联通这写点的路径最小值。每个路径必须在10-1000的范围里面。
方法就是最少生成树+判断路径长度。
输入坐标后,枚举计算点和点之间的距离,如果距离在10-1000里面满足要求,则放进数组里。然后进行克鲁斯卡尔。最后把路径上的值加起来就OK了。
最后还要统计集合大小,来判断是否能构成,不行的话就输出oh!
感觉对比了克鲁斯卡尔和Prim后,克鲁斯卡尔更好用点。可能是因为并查集熟悉点吧。
#include <stdio.h> #include <math.h> #include <algorithm> #define N 105*105 using namespace std; typedef struct { int x,y; double d; }Node; Node a[N]; int fa[N],x[N],y[N]; void InitSet(int n) { for(int i=1;i<=n;i++) fa[i]=i; } int Find(int x) { return fa[x] == x ? x : fa[x] = Find(fa[x]) ; } bool Merge(int u ,int v) { int fu = Find(u) , fv = Find(v) ; if(fu != fv) fa[fv] = fu ; return fu != fv ; } double getdistance(double x1,double y1,double x2,double y2) { return sqrt((double)(x1-x2)*(x1-x2)+(double)(y1-y2)*(y1-y2)); } bool cmp(Node a,Node b) { return a.d<b.d; } int main() { int t; scanf("%d",&t); while(t--) { int n,k=1; scanf("%d",&n); InitSet(n); for(int i=1;i<=n;i++) scanf("%d%d",&x[i],&y[i]); for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) { double dis=getdistance(x[i],y[i],x[j],y[j]); if(dis>=10&&dis<=1000) { a[k].x=i; a[k].y=j; a[k++].d=dis; } } sort(a,a+k,cmp); double sum=0; int cnt=n-1; for(int i=1;i<k;i++) if(Find(a[i].x)!=Find(a[i].y)) { Merge(a[i].x,a[i].y); sum+=a[i].d; cnt--; } if(cnt==0) printf("%.1lf\n",sum*100); else printf("oh!\n"); } return 0; }