HDU - 1875 - 畅通工程再续

相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组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!
主要是建图,然后最小生成树,我用的Kruskal,也很简单。具体请看代码
#include <math.h>
#include <stdio.h>
#include <iostream>
#include <algorithm>
using namespace std;
int f[10005];

struct Node{
	int x, y;
	double distance;
	void solve(int x1, int y1, double d) {//初始化 
		x = x1; y = y1; distance = d;
	}
}S[10005];

struct node{
	int x, y;
}s[105];

double Distance(node a, node b) {//得到两点之间的距离 
	return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}

bool cmp(Node a, Node b) {//排序 
	return a.distance < b.distance;
}

int getf(int v) {
	if(f[v] != v) {
		f[v] = getf(f[v]);
	}
	return f[v];
}
void init(int n) {//初始化 
	for(int i = 1; i <= n; i++) {
		f[i] = i;
	}
}
int main() {
	int N;
	scanf("%d", &N);
	while(N--) {
		int n;
		scanf("%d", &n);
		init(n);
		for(int i = 1; i <= n; i++) {
			scanf("%d %d", &s[i].x, &s[i].y);
		}
		int sub = 0;
		for(int i = 1; i < n; i++) {//此处下标不能从0开始,一定要切记 
			for(int j = i+1; j <= n; j++) {
				double d = Distance(s[i], s[j]);
				if(d < 10 || d > 1000) continue;
				S[sub++].solve(i, j, d);
			}
		}
		double sum = 0;
		sort(S, S+sub, cmp);
		for(int i = 0; i < sub; i++) {
			int t1 = getf(S[i].x);
			int t2 = getf(S[i].y);
			if(t1 != t2) {//比较 
				sum += S[i].distance*100;
				f[t1] = t2;
			}
		}
		int ans = 0;
		for(int i = 1; i <= n; i++) {//最后一步还得需要判断。 
			if(f[i] == i) {
				ans++;
			}
		}
		if(ans != 1) sum = 0;
		if(sum == 0) printf("oh!\n");
		else printf("%.1lf\n", sum);
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值