题目大意:给出n个点的坐标(x,y),要求用线段将n个点连接起来,求最小的线段和。
最小生成树问题,用Kruskal算法进行求解,其中用到了并查集。将所有的点连接,构成一张图,对每一条边进行编号,两点间的距离作为权重。
1 #include <cstdio> 2 #include <algorithm> 3 #include <cmath> 4 #define square(x) (x)*(x) 5 #define MAXN 10000 6 #define POINTN 100+10 7 using namespace std; 8 9 double w[MAXN], point[POINTN][2]; // the weight of edge 10 int u[MAXN], v[MAXN], r[MAXN], p[MAXN]; 11 // u[i] and v[i] save the end points of the ith edge seperately, r[i] save the ith edge of non-decreasing ordered edges 12 13 double distance(double x1, double y1, double x2, double y2) 14 { 15 double t = square(x2-x1) + square(y2-y1); 16 return sqrt(t); 17 } 18 19 int cmp(const int i, const int j) 20 { 21 return w[i] < w[j]; 22 } 23 24 int find(int x) 25 { 26 return p[x] == x ? x : p[x] = find(p[x]); 27 } 28 29 int main() 30 { 31 #ifdef LOCAL 32 freopen("in", "r", stdin); 33 #endif 34 int N; 35 scanf("%d", &N); 36 bool first = true; 37 while (N--) 38 { 39 int n; 40 scanf("%d", &n); 41 for (int i = 0; i < n; i++) 42 scanf("%lf%lf", &point[i][0], &point[i][1]); 43 int k = 0; // the size of edge 44 for (int i = 0; i < n; i++) 45 for (int j = i+1; j < n; j++) 46 { 47 w[k] = distance(point[i][0], point[i][1], point[j][0], point[j][1]); 48 u[k] = i; 49 v[k] = j; 50 k++; 51 } 52 double ans = 0; 53 for (int i = 0; i < n; i++) p[i] = i; 54 for (int i = 0; i < k; i++) r[i] = i; 55 sort(r, r+k, cmp); // sort the edge 56 for (int i = 0; i < k; i++) 57 { 58 int e = r[i]; 59 int x = find(u[e]); 60 int y = find(v[e]); 61 if (x != y) 62 { 63 ans += w[e]; 64 p[x] = y; 65 } 66 } 67 if (first) first = false; 68 else printf(" "); 69 printf("%.2lf ", ans); 70 } 71 return 0; 72 }
代码中用到了间接排序——排序的关键字是对象的“代号”,而不是对象本身,将排序后第i小的边的序号保存在r[i]中。这样对象本身的数据就不需要移动了,比如这道题的u[i]和v[i],自己也就能理解到这点了...代码是照抄别人的,解释还是照抄别人的...人工版的Ctrl-C & Ctrl-V 啊...