原题链接
- 题意:给出 (n <= 1e5) 个网格图点位置,然后让求所有点连起来的最小花费,即特殊的最小生成树,两个点之间相连的花费是 (min(|x_a - x_b|, |y_a - y_b|))
- 题解:好像和之前做过一道dij的cf题类似。首先 (n^2) 建边不可取,那就是先按横坐标排序,然后相邻之间 (|x_i - x_j|)必然是最优的,加入预选,然后再按照 (y) 坐标,然后也是相邻的 (|y_i - y_j|) 是最优的,然后最后就是 (kruskal)。
- 代码:
#include <cstdio>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
typedef long long ll;
const ll inf = 0x3f3f3f3f;
const ll N = 1e5 + 9;
struct edge {
int x, y, w;
}e[N << 2], a[N << 2];
struct node {
int x, y, id;
}p[N];
bool cmp1(node a, node b) {return a.x < b.x;}
bool cmp2(node a, node b) {return a.y < b.y;}
bool cmp3(edge a, edge b) {return a.w < b.w;}
int f[N << 2];
int Find(int x){return f[x] == x?x:f[x] = Find(f[x]);}
signed main() {
int n;scanf("%d", &n);
for (int i = 1; i <= n; i ++) {
scanf("%d%d", &p[i].x, &p[i].y);
p[i].id = i;
}
for (int i = 0; i <= n + 2; i ++) f[i] = i;
sort(p + 1, p + 1 + n, cmp1);
int nn = 0;
for (int i = 1; i < n; i ++) e[++nn] = {p[i].id, p[i + 1].id, abs(p[i].x - p[i + 1].x)};
sort(p + 1, p + 1 + n, cmp2);
for (int i = 1; i < n; i++) e[++nn] = {p[i].id, p[i + 1].id, abs(p[i].y - p[i + 1].y)};
sort(e + 1, e + 1 + nn, cmp3);
int ans =0 ;
for (int i = 1; i <= nn; i ++) {
int fx = Find(e[i].x);
int fy = Find(e[i].y);
if (fx == fy)continue;
f[fx] = fy;
ans += e[i].w;
}
printf("%d
", ans);
}