A128415题解
2026-08-14 19:18:14
发布于:浙江
34阅读
0回复
0点赞
背景:
原题链接
这次八级有史以来最简单(可惜我没考

)。
我这次考七级,下次八级,这次八级简单就代表下次超难,qwq。
此外,建议此题升黄(不过不升也无所谓),毕竟最小生成树模板题难度也有黄。(反正ACGO也是摘用洛谷的,这里直接放洛谷的题目)
思路:
板子题,就把边稍微处理一下就行。用储存每个点的和坐标,根据欧几里得距离计算公式,把每两个点的边的距离都遍历表示一遍,如果不大于,就放入边的数组,最后按最小生成树模板写完即可。
练习最小生成树相关内容请看这里。
最小生成树原理
Prim代码
Kruskal代码
数据范围:
ACGO也是一如既往的没有数据范围,这里提供详细的数据范围(我找的都是洛谷上的)。

代码:
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
pair<int,int>a[510];//储存点的坐标信息
int fa[510];
struct node{
int u,v;//两个节点
double w;//权值,由于涉及开根,所以用double
}k[250000];
bool cmp(node a,node b){
return a.w<b.w;
}
int find(int x){
if (fa[x]==x){
return x;
}
return fa[x]=find(fa[x]);//路径压缩优化
}//最小生成树中并查集find函数
void merge(int x,int y){
fa[find(x)]=find(y);
}//并查集merge函数
int main(){
int n,l;
cin>>n>>l;
for (int i=1;i<=n;i++){
cin>>a[i].first>>a[i].second;//每个点的坐标信息
}
int cnt=0;//边的数组下标
for (int i=1;i<=n;i++){
for (int j=i+1;j<=n;j++){
double o=sqrt(pow(a[i].first-a[j].first,2)+pow(a[i].second-a[j].second,2));//两点距离
if (o>l){
continue;
}//如果大于l,说明此边不能建,跳过
k[++cnt].u=i;
k[cnt].v=j;
k[cnt].w=o;//加边
}
}
sort(k+1,k+1+cnt,cmp);//权值小的优先
for (int i=1;i<=n;i++){
fa[i]=i;
}
double ans=0;
int p=0;//最小生成树已加入边数
for (int i=1;i<=cnt;i++){
if (find(k[i].u)!=find(k[i].v)){//不在一个集合
merge(k[i].u,k[i].v);//融合
ans+=k[i].w;//最小生成树加上边权
p++;//已加边数+1
}
if (p==n-1){
break;
}//由于是树,边数为p-1,到达了说明构建完成,直接结束
}
if (p!=n-1){//边数不等于n-1,说明不存在最小生成树
cout<<"Impossible";
}else{
printf("%.2lf",ans);//保留两位小数
}
return 0;
}
结语:
希望对大家学习OI有帮助!
这里空空如也








有帮助,赞一个