首页 > 技术文章 > 最小切比雪夫距离生成树

lingfunny 2022-06-04 18:03 原文

最小切比雪夫距离生成树

At 的题太智慧辣!!

挺好用的一个科技,因为切比雪夫和曼哈顿可以互化,所以相当于能解决最小曼哈顿距离生成树(大概

百度搜了一下最小曼哈顿距离生成树,看起来比最小切比雪夫距离生成树复杂。

给出点 \((x_1, y_1)\)\((x_2,y_2)\) 的切比雪夫距离定义式:

\[\min(| x_1-x_2|,| y_1-y_2|) \]

最主要的思想:切比雪夫距离的特点就是 \(x\)\(y\) 是分裂开的。那么对于两个点之间的边,没必要去算 \(\min\),可以连接一条长度为 \(|x_1-x_2|\) 和一条长度为 \(|y_1-y_2|\) 的边,取 \(\min\) 直接交给最小生成树做即可(显然最小生成树不会选择大的那条边)。显然此时可以单独对 \(x\)\(y\) 分别考虑,比原来的 \(\min\) 高明到不知道哪里去了。

ARC076B(模板):给定 \(n\) 个点,求最小切比雪夫距离生成树。

考虑对 \(n\) 个点先后按照 \(x\)\(y\) 排序,每次排序后连接相邻的两个点(详见代码)。然后直接跑你喜欢的最小生成树算法。

此处用的是 Kruskal。

// Problem: D - Built?
// From: AtCoder - AtCoder Regular Contest 076
// URL: https://atcoder.jp/contests/arc076/tasks/arc076_b
// Time: 2022-06-03 19:50
// Author: lingfunny

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int mxn = 1e5+10;

int n, tot, fa[mxn];
LL ans;

struct node { int x, y, id; } nd[mxn];
struct edge { int u, v, w; } e[mxn*2];

int find(int x) { return fa[x] < 0 ? x : fa[x] = find(fa[x]); }
inline void merge(int x, int y) {
	int rx = find(x), ry = find(y);
	if(fa[rx] > fa[ry]) swap(rx, ry);
	fa[rx] += fa[ry]; fa[ry] = rx;
}

signed main() {
	scanf("%d", &n);
	for(int i = 1; i <= n; ++i) scanf("%d%d", &nd[i].x, &nd[i].y), nd[i].id = i, fa[i] = -1;
	sort(nd+1, nd+n+1, [](node a, node b) { return a.x < b.x; });
	for(int i = 1; i < n; ++i) e[++tot] = {nd[i].id, nd[i+1].id, nd[i+1].x-nd[i].x};
	sort(nd+1, nd+n+1, [](node a, node b) { return a.y < b.y; });
	for(int i = 1; i < n; ++i) e[++tot] = {nd[i].id, nd[i+1].id, nd[i+1].y-nd[i].y};
	sort(e+1, e+tot+1, [](edge a, edge b) { return a.w < b.w; });
	for(int i = 1; i <= tot && n > 1; ++i) {
		auto [u, v, w] = e[i];
		if(find(u) == find(v)) continue;
		else merge(u, v), --n, ans += w;
	}
	printf("%lld\n", ans);
	return 0;
}

还有,我愿称之为 MCDSTMinimum Chebyshev Distance Spanning Tree) 。

推荐阅读