您的位置:首页 > 其它

HDOJ1875畅通工程--克鲁斯卡尔算法与查并集探骊

2017-09-19 23:05 274 查看
Problem Description

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组RPRush对百岛湖的情况充分了解后,决定在符合条件的小岛间建上桥,所谓符合条件,就是2个小岛之间的距离不能小于10米,也不能大于1000米。当然,为了节省资金,只要求实现任意2个小岛之间有路通即可。其中桥的价格为 100元/米。

 

Input

输入包括多组数据。输入首先包括一个整数T(T <= 200),代表有T组数据。

每组数据首先是一个整数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:按照边的代价将边从小到大排序(代价可能是价钱、
9fea
长度)
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: