题目: 传送门
思路: 给你无向图中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;
}