题解:P8074 [COCI 2009/2010 #7] SVEMIR
lailai0916 · · 题解
题意简述
在三维空间中,给定
任意两点
解题思路
思想
对所有点分别按
利用 Kruskal 算法求最小生成树,时间复杂度为
证明
设原完全图为
对任意割
若该最小值由维度
在所有点按
由于
因此,对任意割存在一条候选边
由最小生成树的 切割性质 可知,必存在一棵最小生成树完全由这些相邻边构成。
参考代码
#include <bits/stdc++.h>
using namespace std;
using ll=long long;
const int N=100005;
struct Point
{
int x,y,z;
}a[N];
struct Edge
{
int u,v,w;
bool operator<(const Edge &x) const{return w<x.w;}
};
vector<Edge> E;
int fa[N],id[N];
int find(int u){return u==fa[u]?u:fa[u]=find(fa[u]);}
ll kruskal(int n)
{
for(int i=1;i<=n;i++)fa[i]=i;
sort(E.begin(),E.end());
ll ans=0,cnt=0;
for(auto [u,v,w]:E)
{
if(cnt==n-1)break;
int x=find(u),y=find(v);
if(x==y)continue;
fa[x]=y;
ans+=w;
cnt++;
}
return ans;
}
void add(int u,int v)
{
int dx=abs(a[u].x-a[v].x),dy=abs(a[u].y-a[v].y),dz=abs(a[u].z-a[v].z);
E.push_back({u,v,min(dx,min(dy,dz))});
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n;
cin>>n;
for(int i=1;i<=n;i++){cin>>a[i].x>>a[i].y>>a[i].z;id[i]=i;}
sort(id+1,id+n+1,[](int u,int v){return a[u].x<a[v].x;});
for(int i=1;i<n;i++)add(id[i],id[i+1]);
sort(id+1,id+n+1,[](int u,int v){return a[u].y<a[v].y;});
for(int i=1;i<n;i++)add(id[i],id[i+1]);
sort(id+1,id+n+1,[](int u,int v){return a[u].z<a[v].z;});
for(int i=1;i<n;i++)add(id[i],id[i+1]);
cout<<kruskal(n)<<'\n';
return 0;
}