题目传送门

Description

给定 $n$ 个点,坐标分别为 $(x_i,y_i)$ ,定义两点距离为 $\sqrt{(x_i-x_j)^2+(y_i-y_j)^2}$,若其小于 $l$ 则可以连边。问是否可以选出 $n-1$ 条满足条件的边,使所有点联通,并求出所有情况的最小值,否则输出 $Impossible$

Solution

一道板子题。显然可以先把每两个点之间的距离求出来,排序后放到自定义结构体里面,用 $Kruskal$ 和并查集跑一遍最小生成树,如果当前长度大于了  $l$ 直接  $break$ ,最后检查一下 $cnt$ 是否等于  $n-1$ 即可。

时间复杂度 $O(n^2)$         空间复杂度 $O(n^2)$

AC Code

#include <bits/stdc++.h>
using namespace std;
constexpr int MAXN=510;
constexpr int MAXL=110;

int n;
double l;
struct Edge{
	int u,v;
	double w;
	void make(int a,int b,int x1,int y1,int x2,int y2)
	{
		u=a,v=b;
		w=sqrt((x1-x2)*(x1-x2)+(y1-y2)*(y1-y2));
		return;
	}
}e[MAXN*MAXN]; int tot=0;
struct Point{
	int x,y;
	void make(int a,int b){x=a,y=b;return;}
}p[MAXN];

bool cmp(Edge pp,Edge qq){ return pp.w<qq.w; }

int f[MAXN];

int find(int s){ return f[s]==s?s:f[s]=find(f[s]); }
void merge(int u,int v)
{
	int fu=find(u),fv=find(v);
	f[fu]=fv;
	return;
}

signed main()
{
	//ios::sync_with_stdio(false),cin.tie(nullptr),cout.tie(nullptr);
	scanf("%d%lf",&n,&l);
	for(int i=1,x,y;i<=n;i++)
	{
		scanf("%d%d",&x,&y);
		p[i].make(x,y);
		f[i]=i;
	}
	for(int i=1;i<=n;i++) for(int j=i+1;j<=n;j++) e[++tot].make(i,j,p[i].x,p[i].y,p[j].x,p[j].y);
	sort(e+1,e+tot+1,cmp);
	int cnt=0;
	double ans=0;
	/*Kruskal*/for(int i=1;i<=tot;i++)
	{
		int u=e[i].u,v=e[i].v;
		double w=e[i].w;
		if(w>l) break;
		if(find(u)!=find(v))
		{
			merge(u,v);
			cnt++; ans+=w;
		}
	}
	if(cnt==n-1) printf("%.2lf",ans);
	else printf("Impossible");
	return 0;
}

Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐