2018年江西理工大学C语言程序设计竞赛 F(最小生成树)

2018年江西理工大学C语言程序设计竞赛 F
31世纪,人类世界的科技已经发展到了空前的高度,星际移民,星际旅游早已经不再是问题。人类已经掌握了开发星系的能力。但是,无论发展到何种地步,资源一直是人们关注的重点。一种新的能源被人类掌握,通过它可以搭建虫洞,实现超光年传输。发展武器。但是虽然这种物质在宇宙海量的存在着,但它对于宇宙的稳定是至关重要的,若过量消耗这种物质,对于宇宙的稳定,星系与星系之间以及星系内部的微妙平衡都会产生巨大的影响。这种物质就是暗物质。
宇宙百科》节选

现在,你所在的星系下有n个主星球居住着人民。为了星系内部的稳定与和平发展,现在需要在n个主星球之间建立空间虫洞,众所周知建立虫洞要消耗大量的暗物质,因此,你想要在n个主星球之间建立联系的情况下尽量少的消耗暗物质。目前你已经知道的是,建立虫洞所需要消耗的暗物质与两个星球之间的距离成正比,比例系数为k。并且,两个星球之间的距离为空间缩点距离。每个星球有它自己的三维物理坐标。不过,现在有一个好消息。你所在的星系掌握了一项新的技术,空间奇点压缩,简单来说就是降维,但是由于技术发展初期不够成熟,只能压缩一维。并且,任意两个主星球之间都可以选择是否进行空间奇点压缩。现在,你想知道,在这n个主星球之间建立连接需要花费的最少暗物质是多少。 空间缩点距离:设两个n维坐标a(x1,x2,x3,xn),b(y1,y2,y3,y4,yn).设距离为s,则s=abs((x1+x2+x3+…+xn)−(y1+y2+y3+…+yn));
以上内容纯属瞎扯,请忽略其真实性

输入
第一行两个整数n和k。(1≤n≤105,1≤k≤103)
接下开n行,每行三个整数x,y,z,其中第i行表示第i个星球在星系中的物理坐标。数据保证没有两个星球处于同一个位置上。(1≤x,y,z≤106)
输出
n个主星球之间建立连接需要花费的最少暗物质。

样例输入
3 2
1 1 6
1 2 9
3 20 8
样例输出
4
提示
样例说明:

星球1和星球2之间压缩第三维

星球2和星球3之间压缩第二维

题目就是给你若干个三维坐标点,两点距离为点坐标和的差值,并且可以空间压缩(两点之间可以选择去掉一维再取差值。)
  • 假设没有空间压缩,那么将所有的点按照坐标的和的值排序,将两两之间的差值相加即为答案
  • 现在考虑空间压缩,可以将三种二维(xy, yz, xz)的按照上述方法都放在一个数组里,最后用 K r u s k a l Kruskal Kruskal跑一边即可
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 10;
typedef long long ll;

int fa[N];
int n, k;
struct node{
	ll x, y, z;
	int id;
}a[N];
struct f{
	int u, v;
	ll dis;
	bool operator<(const f &a) const{		//从大到小
		return a.dis > dis;
	}
} e[N*4];

int find(int x)			//并查集
{
	return fa[x] = (fa[x] == x ? x : find(fa[x]));
}
bool cmp_xyz(node a, node b)    	//自定义排序
{
	return a.x + a.y + a.z < b.x + b.y + b.z;
}
bool cmp_xy(node a, node b)
{
	return a.x + a.y < b.x + b.y;
}
bool cmp_yz(node a, node b)
{
	return a.y + a.z < b.y + b.z;
}
bool cmp_xz(node a, node b)
{
	return a.x + a.z < b.x + b.z;
}

void init()							//把三维的和三种二维的都放入e数组,也即所有可能,
{									//等下直接对e数组Kruskal
	for (int i = 1; i <= n; i++){
		fa[i] = i;
	}
	int ans = 0;
	sort(a, a + n, cmp_xyz);
	for(int i = 1; i < n; i++){
		e[ans++] = (f){a[i].id, a[i - 1].id, a[i].x + a[i].y + a[i].z - a[i - 1].x - a[i - 1].y - a[i - 1].z};
	}
	sort(a, a + n, cmp_xy);
	for(int i = 1; i < n; i++){
		e[ans++] = (f){a[i].id, a[i - 1].id, a[i].x + a[i].y - a[i - 1].x - a[i - 1].y};
	}
	sort(a, a + n, cmp_yz);
	for(int i = 1; i < n; i++){
		e[ans++] = (f){a[i].id, a[i - 1].id, a[i].y + a[i].z - a[i - 1].y - a[i - 1].z};
	}
	sort(a, a + n, cmp_xz);
	for(int i = 1; i < n; i++){
		e[ans++] = (f){a[i].id, a[i - 1].id, a[i].x + a[i].z - a[i - 1].x - a[i - 1].z};
	}
	int pos = n - 1;
	sort(e, e + ans);
}
void kruskal()
{
	ll res = 0;
	ll ans = 4 * n;
	int pos = n - 1;
	for(int i = 0; i < ans && pos > 0; i++){
		int x = find(e[i].u);
		int y = find(e[i].v);
		if(x != y){
			res += e[i].dis;
			fa[x] = y;
			pos--;
		}
	}
	printf("%lld\n", res * k);
}
int main()
{
	scanf("%d%d", &n, &k);
	for (int i = 0; i < n; i++){
		scanf("%lld%lld%lld", &a[i].x, &a[i].y, &a[i].z);
		a[i].id = i + 1;
	}
	init();
	kruskal();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值