八中生成树1 [MST](C++)

本文介绍了一种使用Kruskal算法解决最小生成树问题的方法,结合欧几里得距离计算水管连接费用,并处理校长设定的费用限制。在二维空间中,通过建立并查集和排序边权,确保不形成环路的同时找到最小费用的连接方案。

前言:

        好久没有更新了,最近学习压力有点大,而且队里学的东西越来越变态,所以近期我会试着更新一些难题,至于水题嘛。。。我们训练时就没有水题。。。

题目:

八中草坪上有N个水龙头,位于(x_i,y_i
求将N个水龙头连通的最小费用。
任意两个水龙头可以修剪水管,费用为欧几里得距离的平方。
校长只愿意修费用大于等于C的水管。

输入

第一行给出NC
接下来N行给出点的坐标x,y
1<=N​​​​​​​ <=200
1<=x_i, y_i<=1000
1<=C<=1000000

输出

输出最小费用,如果无解输出-1

样例输入:

3 11
0 2
5 0
4 3

 样例输出:

46 

 思路:

1:这道题用最小生成树解决,

我用的是Kruskal算法:

其思路在于将每条边按边权从小到大排序,

每次取相对小的边,

并查集判断连接该边会不会形成图

如果会,则跳过该边

如不会,则进行操作

2:要用到欧几里得距离的知识;

二维空间公式:S=\sqrt{(x_1-x_2)^2+(y_1-y_2)^2}

代码:

#include<bits/stdc++.h>
using namespace std;
const int N=2010;
int n;
int c;
int fa[N];
int cnt=0;
int ans=0;
int x[N],y[N];

struct edge {
	int x,y;
	int val;
}e[N*N];

int Euclidean_Metric(int x_x,int x_y,int y_x,int y_y) {//欧几里得距离 
	return (x_x-y_x)*(x_x-y_x)+(x_y-y_y)*(x_y-y_y);//由题意,无需开根 
}

void put (int a,int b) {//建树 
	cnt++;
	e[cnt].x=a;
	e[cnt].y=b;
	e[cnt].val=Euclidean_Metric(x[a],y[a],x[b],y[b]);
}

int find(int x) {
	if(fa[x]!=x)
	    fa[x]=find(fa[x]);
	return fa[x];
}

void unite(int x,int y) {//将x,y放入同一个集合中 
	int p=fa[x],q=fa[y];
	if(p!=q)
	    fa[q]=p;
}

bool cmp(edge a,edge b) {//按边权排序 
	return a.val<b.val;
}



void MST_Kruskal() {//求最小生成树 
	int tot=0;//最小生成树边数 

	for(int i=1;i<=cnt;i++) {
		if(find(e[i].x)==find(e[i].y)||e[i].val<c) 
		    continue;//如果会形成图 或 边权小于C ,则跳过	
		//否则进行以下操作: 
		unite(e[i].x,e[i].y); //将该边连接的两点放到同一个集合里,表示两点联通 
		tot++;//边数++ 
		ans+=e[i].val;//加上边权 
	}
	if(tot<n-1)//因为N个点的最小生成树有N-1条边 
	    puts("-1");//tot小于N,则构不成最小生成树 
	else//若能构成,输出代价 
	    printf("%d",ans);
}

int main() {
	scanf("%d%d",&n,&c);
	for(int i=1;i<=n;i++) fa[i]=i;
	for(int i=1;i<=n;i++) 
		scanf("%d%d",&x[i],&y[i]);
	for(int i=1;i<=n;i++) {
		for(int j=i+1;j<=n;j++) {
			put(i,j);
		}
	}
	sort(e+1,e+cnt+1,cmp);
	MST_Kruskal();
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值