Freckles【北京大学复试机试题】【Kruskal】

题目描述

    In an episode of the Dick Van Dyke show, little Richie connects the freckles on his Dad's back to form a picture of the Liberty Bell. Alas, one of the freckles turns out to be a scar, so his Ripley's engagement falls through.      Consider Dick's back to be a plane with freckles at various (x,y) locations. Your job is to tell Richie how to connect the dots so as to minimize the amount of ink used. Richie connects the dots by drawing straight lines between pairs, possibly lifting the pen between lines. When Richie is done there must be a sequence of connected lines from any freckle to any other freckle.

输入描述:

    The first line contains 0 < n <= 100, the number of freckles on Dick's back. For each freckle, a line follows; each following line contains two real numbers indicating the (x,y) coordinates of the freckle.

输出描述:

    Your program prints a single real number to two decimal places: the minimum total length of ink lines that can connect all the freckles.

示例1

输入

复制

3
1.0 1.0
2.0 2.0
2.0 4.0

输出

复制

3.41

题意:输入n,表示有n个点,接下来的n行输入n个点的位置。输出能将所有点连起来的最小长度,就是一个最小生成树的问题

思路:n个点有n*(n-1)/2条边,将这些边按照大小顺序排序,用Kurskal求最小生成树。这道题也是,数据结构比较复杂。

注意:需要注意的一点是,如果要用map,并且map的键为结构体类型,必须要对这个结构体重载小于号,因为map是自动排序的。

#include<iostream>
#include<algorithm>
#include<map>
#include<cmath>
using namespace std;

const int MAXN=101;
struct Point{
	double x;
	double y;
	bool operator< (Point a) const{   //因为用了map<Point,Point>,而map会自动排序所以必须要进行小于运算符的重载 
		if(x==a.x){        
			return y<a.y;
		}
		else{
			return x<a.x;
		}
	} 
}points[MAXN];

struct edge{
	Point from;
	Point to;
	double len;
	bool operator < (edge a) const{
		return len<a.len;
	}
}edges[100000];

map<Point,Point> father;
map<Point,int> height;

void Init(int n){
	for(int i=0;i<n;i++){
		father[points[i]]=points[i];
		height[points[i]]=0;
	}
}

Point Find(Point p){
	if(p.x!=father[p].x||p.y!=father[p].y ){
		father[p]=Find(father[p]);
	}
	return father[p];
}

void Union(Point i,Point j){
	i=Find(i);
	j=Find(j);
	if(i.x!=j.x||i.y!=j.y ){
		if(height[i]>height[j]){
			father[j]=i;
		}
		else if(height[j]>height[i]){
			father[i]=j;
		}
		else{
			father[j]=i;
			height[i]++;
		}
	}
	return ;
}

double Kruskal(int n,int edgenumber){
	Init(n);
	double sum=0;
	sort(edges,edges+edgenumber);
	for(int i=0;i<edgenumber;i++){
		//若不在同一集合,则合并 
		if(Find(edges[i].from).x!=Find(edges[i].to).x || Find(edges[i].from).y!=Find(edges[i].to).y){
			Union(edges[i].from,edges[i].to);
			sum+=edges[i].len;
		}
	}
	return sum;
}

int main(){
	int n;
	scanf("%d",&n);
	int x,y;
	for(int i=0;i<n;i++){
		scanf("%lf%lf",&points[i].x,&points[i].y);
	}
	int m=n*(n-1)/2;
	int k=0;
	for(int i=0;i<n;i++){
		for(int j=i+1;j<n;j++){
			double l=(points[i].x-points[j].x)*(points[i].x-points[j].x)+(points[i].y-points[j].y)*(points[i].y-points[j].y);
			edge temp;
			temp.from=points[i];
			temp.to=points[j];
			temp.len=sqrt(l);
			edges[k++]=temp;
		}
	}
	printf("%.2lf\n",Kruskal(n,k));
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值