这道题考察最小生成树和贪心。
万物皆用kruscal(滑稽)
最小生成树的板子:
void kruscal() {
for(int i=1; i<=n; i++) f[i]=i;
sort(Edge+1,Edge+1+m,cmp);
for(int i=1; i<=m; i++) {
int u=Edge[i].u,v=Edge[i].v;
int k=find(u),l=find(v);
if(k!=l) {
f[k]=l;
sum+=w;
cnt++;
if(cnt==n-1) return;
}
}
}
题目给定N个点需要N-1条隧道使得它们直接或间接的连在一起。
假如我们暴力求解,给它们每个点之间都连一条边,就要连n*(n-1)/2条边,n=1e5时,需要存边数为5*10^9条,肯定会MLE,所以我们需要优化一下。
那么怎么优化呢?删边,删掉没有贡献的边就好了。其实我们不需要每个点都连一条边,只需要相邻的点连一条边就好了。
每一条边是同一维度中的差的绝对值的最小值,那么我们完全不需要建那么多条边,只需要每两个相邻的同一纬度建边,即3*(n-1)条边,总共才300000条边。
比如样例1:它有两个点,我们就需要建3条边,即两个点之间的x轴、y轴、z轴各建一条边。由于题目中给出了绝对值,所以我们最好分别对这些点的各个维度进行的值进行从小到大排序,防止算边的长度时出现负数。
然后我们就需要将这些边存起来。比如第一和第二个点之间有三条边,第二和第三个点之间又有三条边,那么我们就得用到邻接表来存储边,这样才可以保证每一条边都有名字。
最后我们套上kruscal板子就好啦!
完整代码:
扫描二维码关注公众号,回复:
14622005 查看本文章
//两个点的坐标之间最大的差值是2e9,在int类型里面
#include <bits/stdc++.h>
#define MOD 1000000007
#define INF 0x7f7f7f7f
using namespace std;
typedef long long LL;
int n,idx,minn,f[100005];
struct node {
int x,y,z,id;
//node uu(int x,int y,int z,int id):x(x),y(y),z(z),id(id) {}
} point[100005];//存点
struct edge {
int u,v,w;
//node uu(int u,int v,int w):u(u),v(v),w(w) {}
} Edge[300005];//存边
//以x坐标为基准升序
bool cmpx(node a,node b) {
return a.x<b.x;
}
//以y坐标为基准升序
bool cmpy(node a,node b) {
return a.y<b.y;
}
//以z坐标为基准升序
bool cmpz(node a,node b) {
return a.z<b.z;
}
//以两个对应维度之间的长度为基准升序
bool cmpw(edge a,edge b) {
return a.w<b.w;
}
int find(int x) {
return f[x]==x ? x : f[x]=find(f[x]);
}
//克鲁斯卡尔模板
void kruscal() {
for(int i=1; i<=n; i++) f[i]=i;//初始化
int cnt=0;
sort(Edge+1,Edge+idx+1,cmpw);//对边进行升序
//for(int i=1; i<=idx; i++)
//cout<<Edge[i].w<<endl;
for(int i=1; i<=idx; i++) {
int u=Edge[i].u, v=Edge[i].v, w=Edge[i].w;
int k=find(u),l=find(v);
//cout<<k<<" "<<l<<endl;
if(k!=l) {
f[k]=l;
minn+=w;
cnt++;
if(cnt==n-1) return;
}
}
}
//邻接表用于存边
void add(int a,int b,int c) {
Edge[++idx].u=a;
Edge[idx].v=b;
Edge[idx].w=c;
}
//快读
inline int read() {
int date=0,w=1;
char c;
c=getchar();
while(c<'0' || c>'9') {
if(c=='-') w=-1;
c=getchar();
}
while(c>='0' && c<='9') {
date=date*10+(c-'0');
c=getchar();
}
return date*w;
}
int main() {
cin>>n;
for(int i=1; i<=n; i++) {
cin>>point[i].x>>point[i].y>>point[i].z;
point[i].id=i;
}
sort(point+1,point+1+n,cmpx);
for(int i=1; i<n; i++)
add(point[i].id, point[i+1].id, point[i+1].x-point[i].x);
sort(point+1,point+1+n,cmpy);
for(int i=1; i<n; i++)
add(point[i].id, point[i+1].id, point[i+1].y-point[i].y);
sort(point+1,point+1+n,cmpz);
for(int i=1; i<n; i++)
add(point[i].id, point[i+1].id, point[i+1].z-point[i].z);
kruscal();
cout<<minn;
return 0;//完美收尾
}