最小生成树(提前已经有边)

7 篇文章 0 订阅

弗拉塔托邦这个岛国是完全平坦的。不幸的是,弗拉塔托市的公共高速公路系统非常差。弗拉托皮亚政府意识到这一问题,已经修建了一些连接一些最重要城镇的公路。然而,仍然有一些城镇你不能通过公路到达。有必要修建更多的公路,这样就可以在两个城镇之间行驶而不离开公路系统。

弗拉托派城镇的编号是从1到N,而I镇的位置是由笛卡尔坐标(xi,yi)确定的。每条公路连接两个城镇。所有公路(包括原来的公路和将要修建的公路)都沿着直线行驶,因此它们的长度等于城镇之间的笛卡尔距离。所有的公路都可以双向使用。公路可以自由交叉,但司机只能在两条公路尽头的一个城镇的高速公路之间切换。

弗拉托派政府希望将修建新公路的成本降到最低。然而,他们想要保证每个城镇都是高速公路-从其他城镇都可以到达。由于弗拉托邦是如此平坦,一条公路的成本总是与其长度成正比。因此,最便宜的公路系统将是一个最大限度地减少公路总长度的公路系统。

输入

输入由两部分组成。第一部分描述全国所有城镇,第二部分描述所有已经建成的公路。

输入文件的第一行包含一个整数N(1<=N<=750),表示城镇数。下一个N行分别包含两个整数,xi和yi用空格分隔。这些值给出了i的坐标。TH城镇(我从1到N)。坐标的绝对值不大于10000。每个城镇都有一个独特的位置。

下一行包含一个整数M(0<=M<=1000),表示现有公路的数量。下一个M行每一行都包含一对由空格分隔的整数。这两个整数给出了一对已经通过公路连接的城镇编号。每一对城镇最多有一条公路相连。

输出量

为每一条新建公路写一条单线,以便以尽可能短的新公路总长将所有城镇连接起来。每条公路都应该打印出这条公路连接的城镇编号,用一个空间隔开。

如果不需要新建公路(所有城镇都已连接),则应该创建输出文件,但它应该是空的。

样本输入

9
1 5
0 0 
3 2
4 5
5 1
0 4
5 2
1 2
5 3
3
1 3
9 7
1 2

样本输出

1 6
3 7
4 9
5 7
8 3
#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
#define INF 0x3f3f3f3f
typedef long long ll;
//此题不需要开邻接矩阵,超内存
//想一想,dp[i][j]存的点和距离,side存的也是端点和距离,所以可以省去dp[][] 
struct node{
	ll x,y;
	double d;
}side[300000];

struct Node{
	ll x,y;
}dis[751];

ll f[751],cnt;


ll find(ll x){
	ll r=x;
	while(r!=f[r]){
		r=f[r];
	}
	ll j=x;
	while(f[j]!=r){
		x=f[j];
		f[j]=r;
		j=x;
	}
	return r;
}
int cmp(node a,node b){
	return a.d<b.d;
}
int cmp_1(Node a,Node b){
	if(a.x==b.x){
		return a.y<b.y;
	}
	return a.x<b.x;
}
int main(){
	ll n,m,cnt_s=0;
	scanf("%lld",&n);
	for(int i=1;i<=n;i++){
		f[i]=i;
	}
	for(int i=1;i<=n;i++){
		scanf("%lld %lld",&dis[i].x,&dis[i].y);
	}
	cnt=0;
	for(int i=1;i<=n;i++){
		for(int j=i+1;j<=n;j++){
				double s=pow(dis[j].y*1.0-dis[i].y*1.0,2)+pow(dis[j].x*1.0-dis[i].x*1.0,2);
				side[cnt].x=i;
				side[cnt].y=j;
				side[cnt++].d=sqrt(s);
		}
	}
	sort(side,side+cnt,cmp);
	scanf("%lld",&m);
	//将已经建好的加入集合 
	for(int i=1;i<=m;i++){
		ll x,y;
		scanf("%lld %lld",&x,&y);
		ll tx=find(x);
		ll ty=find(y);
		if(tx!=ty){
			f[tx]=ty;
			cnt_s++;
		}
	}
	//如果最小生成树已经生成。。。 
	if(cnt_s>=n-1){
		return 0;
	}
	Node book[751];
	ll cnt_k=0;
	for(int i=0;i<cnt;i++){
		ll tx=find(side[i].x);
		ll ty=find(side[i].y);
		if(tx!=ty){
			f[tx]=ty;
			//存路径 
			book[cnt_k].x=side[i].x;
			book[cnt_k++].y=side[i].y;
			cnt_s++;
			if(cnt_s>=n-1){
				break;
			}
		}
	}
	sort(book,book+cnt_k,cmp_1);
	for(int k=0;k<cnt_k;k++){
		printf("%lld %lld\n",book[k].x,book[k].y);
	}	
	return 0;
}

 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值