平面分治详解 超级详细(附带例题 最近点对问题(给了题目))(UVA10245

double d = min(a, b);

int i = upper_bound(data + q, data + (q + t) / 2, make_pair(x_mid - d, INF)) - data;

int jj = upper_bound(data + (q + t) / 2, data + t, make_pair(x_mid + d, INF)) - data;

for(; i < (q + t) / 2; i++)

{

for(int j = (q + t) / 2; j < jj; j++)

{

if(data[i].first - data[j].first >= d)

{

break;

}

else

{

d = min(d, dist(data[i], data[j]));

}

}

}

return d;

}

int main()

{

int N;

scanf(“%d”, &N);

for(int i = 0; i < N; i++)

{

scanf(“%lf %lf”, &data[i].first, &data[i].second);

}

sort(data, data + N);

double jg = deal(0, N);

printf(“%.4lf\n”, jg);

}

第二种:我们在递归处理的同时,按 y坐标 进行归并排序

这样的话我们无法判断直接判断哪个点的 x坐标 离中间点的 横坐标 距离小于 d ,所以我们遍历所有点,当点的 x坐标 在距离中间点的 横坐标 距离小于 d 时进行处理,处理方法为,对一定范围的点,进行遍历比较,如下图

在这里插入图片描述

【相当于我们对于所有点遍历一次,如果 x坐标 在范围内,我们便对阴影区域进行遍历,由于有 d 的限制,所以除去自身,该矩形阴影内最多还有 5 个点。】

缺点:我们遍历了所有点,有 x坐标 距离中间点横坐标超过 d 的多余情况

代码如下(这种在P1429中所耗 1.19s / 8.03MB / 1.45KB )

double deal(int q, int t)

{

if(t - q == 1)

{

return INF;

}

double x_mid = data[(q+t)/2].first;

double a = deal(q, (q + t) / 2);

double b = deal((q + t) / 2, t);

double d = min(a, b);

inplace_merge(data + q, data + (q + t) / 2, data + t, cmp);

vector dian;

for(int i = q; i < t; i++)

{

if(data[i].first <= x_mid - d || data[i].first >= x_mid + d)

{

continue;

}

for(int j = dian.size() - 1; j >= 0; j–)

{

if(data[i].second - data[dian[j]].second >= d)

{

break;

}

d = min(d, dist(data[i], data[dian[j]]));

}

dian.push_back(i);

}

return d;

}

第三种:因为同边的点的最小值已经求出为 d ,所以不用 同边 的之间再次比较,所以我们可以分开两个vector容器分别存左边和右边的 x坐标 在范围内的点

但是这种会产生一种问题,如果在 中间点的横坐标 的点,我们不知道它属于左边还是右边,所以我们左右两边都得存放,且要和左右两边都比较一次

这种优化很不明显,甚至当在中间点的横坐标上的点多了的时候会退化,且原本范围内也就只用匹配最多五次,改了也就省了一两次匹配,还增加了大量代码量

缺点多着

代码如下( 1.58s / 8.07MB / 2.25KB )

double deal(int q, int t)

{

if(t - q == 1)

{

return INF;

}

double x_mid = data[(q+t)/2].first;

double a = deal(q, (q + t) / 2);

double b = deal((q + t) / 2, t);

double d = min(a, b);

inplace_merge(data + q, data + (q + t) / 2, data + t, cmp);

vector right;

vector left;

for(int i = q; i < t; i++)

{

if(data[i].first <= x_mid - d || data[i].first >= x_mid + d)

{

continue;

}

if(data[i].first <= x_mid)

{

left.push_back(i);

for(int j = right.size() - 1; j >= 0; j–)

{

if(i == left[j])

{

continue;

}

if(data[i].second - data[right[j]].second >= d)

{

break;

}

else

最后更多分享:前端字节跳动真题解析

or(int j = right.size() - 1; j >= 0; j–)

{

if(i == left[j])

{

continue;

}

if(data[i].second - data[right[j]].second >= d)

{

break;

}

else

最后更多分享:前端字节跳动真题解析
  • [外链图片转存中…(img-cjJAUmGw-1718097470184)]
  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值