一、内容

 相信大家都听说一个“百岛湖”的地方吧,百岛湖的居民生活在不同的小岛中,当他们想去其他的小岛时都要通过划小船来实现。现在政府决定大力发展百岛湖,发展首先要解决的问题当然是交通问题,政府决定实现百岛湖的全畅通!经过考察小组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的2个点就添加一点边。 最后求一下是否有最小生成树即可。

三、代码

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
const int N = 105;
struct Node {
	double x, y;
} p[N];
int t, n;
double ans, g[N][N], d[N];
bool vis[N];
double getD(int i, int j) {
	double x = p[i].x - p[j].x;
	double y = p[i].y - p[j].y;
	return sqrt(x*x + y*y);	
}
bool prime() {
	ans = 0;
	for (int i = 1; i <= n; i++)d[i] = 1e15;
	memset(vis, false, sizeof(vis));
	for (int i = 0; i < n; i++) {
		int t = -1;
		for (int j = 1; j <= n; j++) {
			if(!vis[j] && (t == -1 || d[t] > d[j])) t = j;
		}
		vis[t] = true;
		if (i && d[t] > 1e14) return false;//代表无法构成 
		if (i) ans += d[t];
		for (int j = 1; j <= n; j++) d[j] = min(d[j], g[t][j]);
	}
	return true;
}
int main() {
	scanf("%d", &t);
	while (t--) {
		scanf("%d", &n);
		for (int i = 1; i <= n; i++) scanf("%lf%lf", &p[i].x, &p[i].y);
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++) g[i][j] = 1e15;
		for (int i = 1; i <= n; i++) {
			for (int j = i + 1; j <= n; j++) {
				double t = getD(i, j);
				if (t >= 10 && t <= 1000) g[i][j] = g[j][i] = t;
			}
		}
		if (prime()) printf("%.1lf\n", ans * 100);
		else printf("oh!\n"); 
	}
	return 0;
}