博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
曼哈顿距离的最小生成树
阅读量:6828 次
发布时间:2019-06-26

本文共 3075 字,大约阅读时间需要 10 分钟。

最近测试有一道这样的题目,由于我以前看过怎么做,但是又不确定,所以就把做法的正确性证明了之后再做的。结果还是写挂了,只对了一个点。

算法

对于每个点,以它为中心把平面分成八个,每个面里面找一个距离它最近的点连一条边,然后做最小生成树即可。

为什么这样是对的呢?

250821578905493.png

如图,对于点\(O\)的其中一个平面,假设点\(A\)是离它最近的点,\(B\)点不是最近的点,我们可以证明,最小生成树里面可以不要\(OB\)这条边。假设有\(OB\)这条边,我们完全可以用\(OA+AB\)来代替,而且答案不会差。注意,这里是曼哈顿距离,所以\(OA+AB \leq OB\),取到等号是的图如下:

250822094845485.png

然后我们就可以各种搞了,我们可以写离散化的树状数组或者是动态开结点的线段树,我偏向于后者,因为思维复杂度小,尽管可能会慢一点(经测,是树状数组的2.2倍)。

好吧,我错了。离散化其实更好搞,我们可以先把所以可能的坐标存进一个数组,用的时候lower_bound就可以定位了,比线段树爽多了。

简要代码

struct Node {    Node* s[2];    pair
key; void update() { key = make_pair(INF, -1); if (s[0]) tension(key, s[0]->key); if (s[1]) tension(key, s[1]->key); }};Node mem[MAXN * LOGUPPER];Node* curMem;bool cmp(const Point &a, const Point &b) { if (a.first.second != b.first.second) return a.first.second > b.first.second; //return a.second > b.second; return a.first.first > b.first.first;}void modify(Node* &idx, int L, int R, int x, pair
val) { if (idx == NULL) { idx = curMem ++; //idx = new Node; idx->s[0] = idx->s[1] = NULL; idx->update(); } if (L == R) { tension(idx->key, val); } else { int M = (L + R) >> 1; if (x <= M) modify(idx->s[0], L, M, x, val); else modify(idx->s[1], M + 1, R, x, val); idx->update(); }}pair
query(Node* &idx, int L, int R, int x, int y) { if (idx == NULL) return make_pair(INF, -1); if (x <= L && y >= R) return idx->key; int M = (L + R) >> 1; pair
ret = make_pair(INF, -1); if (x <= M) tension(ret, query(idx->s[0], L, M, x, y)); if (y > M) tension(ret, query(idx->s[1], M + 1, R, x, y)); return ret;}void build() { sort(A + 1, A + 1 + n, cmp); curMem = mem; Node* root = NULL; for (int i = 1; i <= n; i ++) { int tmp = A[i].first.first - A[i].first.second; pair
result = query(root, -UPPER, UPPER, tmp, UPPER); int tmp2 = A[i].first.first + A[i].first.second; if (result.second != -1) Graph::getOneEdge(result.second, A[i].second, result.first - tmp2); modify(root, -UPPER, UPPER, tmp, make_pair(tmp2, A[i].second)); }}int main() { freopen("travel.in", "r", stdin); freopen("travel.out", "w", stdout); scanf("%d", &n); bool test56 = true; for (int i = 1; i <= n; i ++) { scanf("%d%d", &A[i].first.first, &A[i].first.second); A[i].first.first -= UPPER >> 1; A[i].first.second -= UPPER >> 1; if (A[i].first.first != 1) test56 = false; A[i].second = i; } { for (int i = 0; i < 2; i ++) { for (int j = 0; j < 2; j ++) { build(); for (int i = 1; i <= n; i ++) swap(A[i].first.first, A[i].first.second); } for (int i = 1; i <= n; i ++) { Point tmp = A[i]; A[i].first.first = tmp.first.second; A[i].first.second = - tmp.first.first; } } }

转载于:https://www.cnblogs.com/wangck/p/4455319.html

你可能感兴趣的文章
我的友情链接
查看>>
我的友情链接
查看>>
可执行JAR读写内外文件
查看>>
Handbook of Constraints Programming——Chapter4 Backtracking Search Algorithms-Preliminaries
查看>>
[转载] 信息系统项目管理师视频教程——14 项目进度管理
查看>>
linux 解压文件
查看>>
Ansible入门
查看>>
SVN学习总结(1)——SVN简介及入门使用
查看>>
浅谈linux性能调优之五:调优软raid
查看>>
Android sdk下载缓慢解决方式
查看>>
IBM TPC强化中国建设银行存储管理能力
查看>>
常用ftp子命令的总结
查看>>
正则表达式
查看>>
在 JS 中使用 fetch 更加高效地进行网络请求
查看>>
javascript 分页算法
查看>>
android手机root后的安全问题
查看>>
bat改ip
查看>>
SpringBoot之在Servlet2.5容器中部署war应用
查看>>
项目申请文档提纲
查看>>
加密解密第二章:ollydbg用法
查看>>