[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;
}

AC记录

posted @ 2023-10-05 08:19  ccrui  阅读(10)  评论(0)    收藏  举报