题目:在一个平面上有很多点,其中一些点已经被直线段连接,现在要把所有点连成一个整体,
要求新加入的直线段长度和最小。
分析:最小生成树。这里使用kruskal算法,先把一直线段的集合合并(并查集),然后在计算即可。
说明:╮(╯▽╰)╭。
#include <algorithm> #include <iostream> #include <cstdlib> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int smap[755][755]; typedef struct p_node { int x,y; }point; point p[755]; int dist(point a, point b) { return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y); } typedef struct d_node { int point1; int point2; int weight; }enode; enode edge[565000]; //union_set int sets[755]; int rank[755]; void set_inital(int a, int b) { for (int i = a; i <= b; ++ i) { rank[i] = 0; sets[i] = i; } } int set_find(int a) { if (a != sets[a]) sets[a] = set_find(sets[a]); return sets[a]; } void set_union(int a, int b) { if (rank[a] < rank[b]) sets[a] = b; else { if (rank[a] == rank[b]) rank[a] ++; sets[b] = a; } } //end_union_set int cmp_e(enode a, enode b) { return a.weight < b.weight; } void kruskal(int n) { set_inital(1, n); int r = 0,uni = 0; for (int i = 1; i <= n; ++ i) for (int j = 1; j < i; ++ j) if (!smap[i][j]) { edge[r].point1 = j; edge[r].point2 = i; edge[r].weight = dist(p[i], p[j]); r ++; }else { int A = set_find(i); int B = set_find(j); if (A != B) { set_union(A, B); uni ++; } } if (uni+1 == n) { printf("No new highways need\n"); return; } sort(edge, edge+r, cmp_e); int add = 0; for (int i = 0; i < r; ++ i) { int A = set_find(edge[i].point1); int B = set_find(edge[i].point2); if (A != B) { set_union(A, B); printf("%d %d\n",edge[i].point1,edge[i].point2); if (uni++ == n-1) { printf("No new highways need\n"); return; } } } } int main() { int t,n,m,a,b; while (scanf("%d",&t) != EOF) while (t --) { scanf("%d",&n); for (int i = 1 ; i <= n; ++ i) scanf("%d%d",&p[i].x,&p[i].y); scanf("%d",&m); memset(smap, 0, sizeof(smap) ); for (int i = 1 ; i <= m; ++ i) { scanf("%d%d",&a,&b); smap[a][b] = smap[b][a] = 1; } kruskal(n); if (t) printf("\n"); } return 0; }
时间: 2024-12-06 04:32:46