[ABC065D] Built?题解
看到只要联通就行了,一下就想到了 MST。
首先想到的是暴力的思路,但要建 \(\frac{n(n+1)}{2}\) 条边,在 \(n\le 10^{5}\) 的数据范围下就会喜提 MLE。
这时我们想到了一个贪心的思路,可以先把原数组按 \(x\) 排序,很容易发现相邻两个的差是最小的,所以我们只要建 \(n-1\) 条边,每条边的边权都为 \(x_{i}-x_{i-1}\)。
但因为花费还与 \(y\) 有关,所以同理我们把原数组按 \(y\) 排序,再建 \(n-1\) 条边即可,每条边的边权都为 \(y_{i}-y_{i-1}\)。
AC 代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
int fa[100001],n,k,m,cnt;
double ans;
struct nnn{
int x,y,nn;
}xx[3010000];
struct edge{
int u,v;
int w;
}v[3010000];
bool cmp1(nnn x,nnn y){//按x排序的cmp
return x.x<y.x;
}
bool cmp2(nnn x,nnn y){//按y排序的cmp
return x.y<y.y;
}
bool cmp(edge x,edge y){
return x.w<y.w;
}
int find(int x){
while(x!=fa[x])x=fa[x]=fa[fa[x]];
return x;
}
int kruskal(){
sort(v,v+m,cmp);
for(int i=0;i<m;i++){
int fu=find(v[i].u),fv=find(v[i].v);
if(fu==fv)continue;
ans+=v[i].w;
fa[fv]=fu;
cnt++;
//cout<<cnt<<endl;
if(cnt==n-1)return ans;
}
return -1;
}
int x[2100001],y[100001],z[100001];
signed main(){
cin>>n;
for(int i=0;i<=n;i++)fa[i]=i;
for(int i=1;i<=n;i++){
cin>>xx[i].x>>xx[i].y;
xx[i].nn=i;
}
sort(xx+1,xx+n+1,cmp1);//按x排序
for(int i=1;i<n;i++){//相邻两个建边
int j=i+1;
double s=abs(xx[i].x-xx[j].x);
v[m]=edge{xx[i].nn,xx[j].nn,s};
m++;
}
sort(xx+1,xx+n+1,cmp2);//按y排序
for(int i=1;i<n;i++){//相邻两个建边
int j=i+1;
double s=abs(xx[i].y-xx[j].y);
v[m]=edge{xx[i].nn,xx[j].nn,s};
m++;
}
//cout<<m<<endl;
int aa=kruskal();//最小生成树kruskal
printf("%d",aa);
return 0;
}

浙公网安备 33010602011771号