Problem Description
相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。
Input
输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。
每组数据首先是一个整数C(C <= 100),代表小岛的个数,接下来是C组坐标,代表每个小岛的坐标,这些坐标都是 0 <= x, y <= 1000的整数。
Output
每组输入数据输出一行,代表建桥的最小花费,结果保留一位小数。如果无法实现工程以达到全部畅通,输出”oh!”.
Sample Input
2 2 10 10 20 20 3 1 1 2 2 1000 1000
Sample Output
1414.2 oh!解题思路:很明显这道题是赤裸裸的求最小生成树问题,而且生成的图是稀疏图,妥妥的克鲁斯卡尔算法。判断两点之间是否有连线的条件就是距离是否在10到1000之间。设置两个数据结构,一个是点的Node,还有一个是边的,Edge对象的start和end代表的是点的标号(1~N)。一条线段有两个端点,通过Find函数判断这两个端点是否在一个集合里面,这种方法叫做查并集,方法大同小异:首先,设置并初始化一个Father函数,Father[i]=j说明i节点的下一个节点是j节点。如果Father[i]=i说明i节点是这个集合的代表节点。如果Find(Edge[i].start)=Find(Edge[i].end)说明如果加上Edge[i]这条边就构成了一个回路。由此我总结了克鲁斯卡尔算法的步骤:step1:用结构体规定边的数据结构step2:按照边的代价将边从小到大排序(代价可能是价钱、长度)step3: 用查并集的方法判断边的两个端点是否在一个集合里面,若不是,将start所在集合的代表元素设置为end所在集合代表元素的下一个节点,每添加一条边,计数器加一step4: 如果计数器的值小于N-1,说明有点是不可达的。OK,撒刷撒花~完美!!!#include<iostream> #include<algorithm> #include<cmath> using namespace std; int Father[105]; typedef struct _Node//点 { int x, y; }_Node; _Node Node[105]; typedef struct _Edge//边 { int start; int end; double length; }_Edge; _Edge Edge[100005]; bool cmp(_Edge a, _Edge b) { return a.length < b.length; } double get_d(_Node a, _Node b) { return sqrt(pow(a.x - b.x, 2) + pow(a.y - b.y,2)); } int Find(int x) { while (Father[x] != x) { x = Father[x]; } return x; } void Union(int x, int y) { int i = Find(x); int j = Find(y); if (i != j) { Father[i] = j; } } int main() { int T; int C; double distance; cin >> T; while (T--) { cin >> C; int total = C - 1;//如果能够成最小生成树,会有total条边 double sum = 0.0; for (int i = 1; i <= C; i++) { cin >> Node[i].x >> Node[i].y; } int k = 1; for (int i = 1; i <= C; i++) { for (int j = i + 1; j <= C; j++) { distance = get_d(Node[i], Node[j]); if (distance >= 10 && distance <= 1000) { Edge[k].start = i; Edge[k].end = j; Edge[k++].length = get_d(Node[i], Node[j]); } } } sort(Edge + 1, Edge + k + 1, cmp);//将Edge矩阵按照length从小到大的顺序排列 for (int i = 1; i <= C; i++)//初始化并查集 { Father[i] = i; } for (int i = 1; i <= k; i++) { if (Find(Edge[i].start) != Find(Edge[i].end)) { Union(Edge[i].start, Edge[i].end); sum += Edge[i].length; total--; } } sum *= 100.0; if (total != 0) { cout << "oh!" << endl; } else { printf("%.1f\n", sum); } } return 0; }