【最小生成树专题】HDU 1285 畅通工程再续 (用坐标算距离)

http://acm.hdu.edu.cn/showproblem.php?pid=1875

畅通工程再续

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 38221    Accepted Submission(s): 12808

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!

Source

2008浙大研究生复试热身赛(2)——全真模拟

Recommend

lcy   |   We have carefully selected several similar problems for you:  1102 1272 1301 1162 1325 
 

思路

题目大意:给你几个岛的坐标,只有两个岛的距离在10~1000米范围内的岛才能建立道路。每米道路花费100元。

问:能否建立连接全部岛屿的道路。若能,输出建立道路的最小花费;若不能输出"oh!"。

方法:裸的Kruskal,Debug了数个小时,一直TLE超时,后来发现    while(scanf("%d",&t)){忘记写!=EOF了

 

AC Code

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm> 
using namespace std;
const int nmax=110;
const int mmax=10010; 
int n,m;//点数、边数 
struct Edge{
	int u,v;//起点、终点、
	double val;//边权 
}edge[mmax];
 
bool cmp(Edge a,Edge b){
	return a.val<b.val; //按照边权从小到大排序,求最小生成树 
} 
 
struct Point{
	int x,y;//小岛的坐标 
}p[nmax];

double getDist(int i,int j){//得到两个小岛间的距离 
	return sqrt((p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y));
} 
int father[nmax];

int findFather(int u){
	if(u==father[u]) return u;
	else{
		int f=findFather(father[u]);
		father[u]=f;
		return f;
	}
}

void init(int n){
	for(int i=0;i<n;++i){
		father[i]=i;
	}
} 
void Kruskal(){//返回最小生成树的边权和
    //init(n); 
    sort(edge,edge+m,cmp); 
	int cnt=0;//有效合并次数 
	double ans=0;//最小边权和 
	for(int i=0;i<m;i++){//遍历m条边
		int fu=findFather(edge[i].u);
		int fv=findFather(edge[i].v);
		if(fu!=fv){
			father[fu]=fv;
			ans+=edge[i].val;
			cnt++;
			if(cnt==n-1)//合并了N-1条边,已经找到了最小生成树
				break; 
		}
	} 
	if(cnt==n-1)//找到最小生成树
		printf("%.1lf\n",ans*100);
	else		//图不连通 
		printf("oh!\n");
}
 
int main(int argc, char** argv) {
	int t;
	while(scanf("%d",&t)!=EOF){
		while(t--){
			memset(father,0,sizeof(father));
			scanf("%d",&n);
			init(n);
			for(int i=0;i<n;i++){
				scanf("%d %d",&p[i].x,&p[i].y);
			}
			int id=0;//有id条边 
			for(int i=0;i<n-1;++i){
				for(int j=i+1;j<n;++j){
					double len=getDist(i,j);
					//printf("Dist:%.5lf\n",len); 
					if(len>=10.0 &&len<=1000.0){
						edge[id].u=i;edge[id].v=j;edge[id].val=len;
						id++;
					}
				}
			}
			m=id;
			Kruskal();
		}
	}
	return 0;
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值