题意:给出n个点和他们的坐标,用一支墨水笔将他们连通,要求墨水浪费最少
典型的最小生成树问题,用kruskal问题(包括并查集)
#include<stdio.h> #include<math.h> #include<stdlib.h> typedef struct Node{ int s; // 起点 int d; // 终点 double dis; // 距离 }Edge; // 边结构体 Edge E[4950]; // 100个点最多4950条边 int father[100]; int n; // 点个数 int cnt = 0; // 边个数 void init() { for(int i = 0;i<n;i++) father[i] = i; } int findfather(int n) { if(father[n] == n) return n; else return findfather(father[n]); } int cmp(const void*a,const void*b) { Edge *x = (Edge *)a; Edge *y = (Edge *)b; return x->dis*1000 - y->dis*1000; } double kruskal() { double ans = 0; qsort(E,cnt,sizeof(Edge),cmp); int j = 0; // 已添加的边的个数 for(int i = 0;i<cnt;i++) { if(j == n-1) break; int x,y; //合并 x = findfather(E[i].s); y = findfather(E[i].d); if(x!=y) { father[x] = y; ans += E[i].dis; j++; } else continue; } return ans; } int main() { scanf("%d",&n); double c[n][2]; init(); // father初始化 for(int i = 0;i<n;i++) scanf("%lf%lf",&c[i][0],&c[i][1]); for(int i = 0;i<n;i++) { for(int j = i+1;j<n;j++) { E[cnt].s = i; E[cnt].d = j; E[cnt].dis = sqrt( (c[i][0]-c[j][0]) * (c[i][0]-c[j][0]) + (c[i][1]-c[j][1]) * (c[i][1]-c[j][1]) ); cnt ++; } } printf("%.2lf",kruskal()); return 0; }