试题I:村庄建设 25'

题目: 传送门
思路: 给你无向图中n个节点,求最小生成树边权和,直接套Kruskal(优先队列+并查集)
在这之前用 n 2 n^2 n2的复杂度把 n n n个节点两两成的边以及代价加入优先队列就OK了
Code:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<vector>
#include<queue>
using namespace std;

typedef long long ll;
const int maxn = 10000007;
const int mod = 10000;

int n;//number of villages
int x[1007], y[1007], h[1007];//info of each village
int root[maxn];
int in_edges = 0;
double ans = 0;
struct node {
    
    
	int from, to;
	double dis;
	bool operator < (const node& other) const {
    
    
		return dis > other.dis;
	}
} edges[maxn];
priority_queue<node> q;

inline int read() {
    
    //快读
	register int f=1, x=0;
	char c=getchar();
	while (c < '0' || c > '9') {
    
    if (c == '-')  f*=-1;  c = getchar();}
	while (c>='0' && c<='9') {
    
    x = x*10 + c-'0';  c = getchar();}
	return x*f;
}
inline double get_cost(int a, int b) {
    
    //calculate cost to connection of village a and b
	return sqrt((x[a]-x[b])*(x[a]-x[b]) + (y[a]-y[b])*(y[a]-y[b])) + (h[a]-h[b])*(h[a]-h[b]);
}
void init() {
    
    
	for (int i=1;i<=n;i++) {
    
    
		root[i] = i;
	}
}
int find_root(int x) {
    
    
	if (x == root[x])
		return x;
	return root[x] = find_root(root[x]);
}
void merge(int a, int b) {
    
    
	int fa = find_root(a), fb = find_root(b);
	if (fa != fb) root[fb] = fa;
}
int main()
{
    
    
	n = read();
	for (int i=1;i<=n;i++) {
    
    
		x[i] = read();
		y[i] = read();
		h[i] = read();
	}
	init();
	for (int i=1;i<=n-1;i++) {
    
    
		for (int j=i+1;j<=n;j++) {
    
    
			q.push(node {
    
    i, j, get_cost(i, j)});
		}
	}

	while (!q.empty()) {
    
    
		if (in_edges == n-1)  break;//already enough
		node t = q.top();q.pop();
		if (find_root(t.from) != find_root(t.to)) {
    
    
			merge(t.from, t.to);
			ans += t.dis;
			in_edges++;
		}
	}
	//四舍五入
	ans = ans * 100;
	ans = round(ans);
	ans /= 100;
	printf("%.2lf\n", ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/u010017231/article/details/105625112
25