C++ 曼哈顿度量中的最小距离
我试图找到(x,y)中的最小距离。我正在搜索有关这方面的信息。但我什么也没找到C++ 曼哈顿度量中的最小距离,c++,algorithm,optimization,C++,Algorithm,Optimization,我试图找到(x,y)中的最小距离。我正在搜索有关这方面的信息。但我什么也没找到 #include<bits/stdc++.h> using namespace std; #define st first #define nd second pair<int, int> pointsA[1000001]; pair<int, int> pointsB[1000001]; int main() { int n, t; unsigned long
#include<bits/stdc++.h>
using namespace std;
#define st first
#define nd second
pair<int, int> pointsA[1000001];
pair<int, int> pointsB[1000001];
int main() {
int n, t;
unsigned long long dist;
scanf("%d", &t);
while(t-->0) {
dist = 4000000000LL;
scanf("%d", &n);
for(int i = 0; i < n; i++) {
scanf("%d%d", &pointsA[i].st, &pointsA[i].nd);
}
for(int i = 0; i < n; i++) {
scanf("%d%d", &pointsB[i].st, &pointsB[i].nd);
}
for(int i = 0; i < n ;i++) {
for(int j = 0; j < n ; j++) {
if(abs(pointsA[i].st - pointsB[j].st) + abs(pointsA[i].nd - pointsB[j].nd) < dist) {
dist = abs(pointsA[i].st - pointsB[j].st) + abs(pointsA[i].nd - pointsB[j].nd);
}
}
printf("%lld\n", dist);
}
}
}
输出:
5
4
我的解决方案(请注意,为简单起见,我不关心曼哈顿区的溢出问题,因此它不适用于无符号长字符:
#包括
#包括
#包括
#包括
#包括
#包括
typedef std::对点;
typedef std::向量点列表;
静态内联布尔cmp_x(常数点a、常数点b)
{
如果(a.首先b.first){
返回false;
}否则{
返回a.secondb秒){
返回false;
}否则{
返回a.firstfirst,&it->second)!=2){
std::abort();
}
断言(它->秒>0);
}
点列表点SB(N);
for(PointsList::iterator it=pointsB.begin(),endi=pointsB.end();it!=endi;++it){
如果(扫描(“%d%d”,&it->first,&it->second)!=2){
std::abort();
}
断言(它->秒<0);
}
排序(pointsA.begin()、pointsA.end()、cmp_by_y);
排序(pointsB.begin()、pointsB.end()、cmp_by_y);
常量点列表::常量迭代器min_a_by_y=pointsA.begin();
常量点列表::常量迭代器max_b_by_y=(pointsB.rbegin()+1).base();
断言(*max_b_by_y==pointsB.back());
无符号区=曼哈顿区(*min_a_by_y,*max_b_by_y);
const unsigned diff_x=std::abs(minu a_by_y->first-max_b_by_y->first);
常数无符号最佳_diff_y=dist-diff_x;
const int max_y_for_a=max_b_by_y->秒+距离;
const int min_y_for_b=min_a_by_y->second-dist;
PointsList::迭代器;
对于(it=pointsA.begin()+1;it!=pointsA.end()&&it->second second>=min\u y\u for_b;+rit){
}
if(rit!=pointsB.rend()){
pointsB.erase(pointsB.begin(),(rit+1.base());
}
std::sort(pointsA.begin()、pointsA.end()、cmp_by_x);
std::sort(pointsB.begin()、pointsB.end()、cmp_by_x);
对于(size_t j=0;diff_x>0&&j=cur_a_point.second);
const int diff_x=距离-最佳差异;
const int min_x=当前点。第一个-差值x+1;
const int max_x=当前第一个点+diff_x-1;
常量点搜索项=std::make_pair(max_x,std::numeric_limits::min());
PointsList::const\u迭代器可能在\u it=std::下限附近(pointsB.begin()、pointsB.end()、搜索项、cmp\u by\u x);
for(PointsList::const\u reverse\u迭代器rit(可能在它附近);rit!=pointsB.rend()&&rit->first>=min\ux;++rit){
const unsigned cur_dist=曼哈顿区(cur_a_point,*rit);
如果(当前距离<距离){
dist=cur_dist;
}
}
}
printf(“%u\n”,dist);
}
}
我的机器上的基准测试(Linux+i7 2.70 GHz+gcc-Ofast-march=native):
$make bench
时间。/test1test1\u res
实数0m7.846s
用户0m7.820s
系统0m0.000s
时间./test2test2\u res
实际0.605s
用户0.590秒
sys 0m0.010s
test1
是您的变体,test2
是我的变体。您需要学习如何编写函数以及如何使用容器。以您当前的编码风格,不可能得到更好的解决方案
问题是更好的解决方案是递归方法。按X坐标对点进行排序。现在递归地将集合一分为二,并确定每一半内的最近距离以及两个点之间的最近距离
最后一部分是有效的,因为两半都是按X排序的。将左半部分的最后一个值与右半部分的第一个值进行比较,可以得到一个很好的距离上限。因此,您可以进行一个非常简单的优化,可以节省大量时间
由于您声明集合A中的所有点的y>0,集合B中的所有点的y<0,您可以立即放弃A中y>Mindsist的所有点和B中y<-Mindsist的所有点。这些点永远不能比当前最近的一对更近:
for(int i = 0; i < n ;i++) {
if (pointsA[i].nd > dist)
continue; // <- this is the big one
for(int j = 0; j < n ; j++) {
if (pointsB[j].nd < -dist)
continue; // <- helps although not as much
if(abs(pointsA[i].st - pointsB[j].st) + abs(pointsA[i].nd - pointsB[j].nd) < dist) {
dist = abs(pointsA[i].st - pointsB[j].st) + abs(pointsA[i].nd - pointsB[j].nd);
}
}
printf("%lld\n", dist);
}
for(int i=0;idist)
继续;//在a组和B组中保留一个候选列表,最初包含整个输入。取y中最接近的一对,取a的最小y和最大y B,计算曼哈顿距离,并从候选列表中删除y大于上限的任何候选列表。这可能会删除输入,或者可能基本上没有影响,但实际上是无效的和廉价的第一步
现在,在x和y中对剩余的候选项进行排序。这将在y中为您提供一个分离列表,在x中为一个混合列表,即O(N log N),其中N已被削减,希望但不一定是第一步。
对于每个点,现在计算其在y(平凡)中的最近邻点和在x中的最近邻点
#include <cstdlib>
#include <cstdio>
#include <cassert>
#include <vector>
#include <limits>
#include <algorithm>
typedef std::pair<int, int> Point;
typedef std::vector<std::pair<int, int> > PointsList;
static inline bool cmp_by_x(const Point &a, const Point &b)
{
if (a.first < b.first) {
return true;
} else if (a.first > b.first) {
return false;
} else {
return a.second < b.second;
}
}
static inline bool cmp_by_y(const Point &a, const Point &b)
{
if (a.second < b.second) {
return true;
} else if (a.second > b.second) {
return false;
} else {
return a.first < b.first;
}
}
static inline unsigned manhattan_dist(const Point &a, const Point &b)
{
return std::abs(a.first - b.first) +
std::abs(a.second - b.second);
}
int main()
{
unsigned int n_iter = 0;
if (scanf("%u", &n_iter) != 1) {
std::abort();
}
for (unsigned i = 0; i < n_iter; ++i) {
unsigned int N = 0;
if (scanf("%u", &N) != 1) {
std::abort();
}
if (N == 0) {
continue;
}
PointsList pointsA(N);
for (PointsList::iterator it = pointsA.begin(), endi = pointsA.end(); it != endi; ++it) {
if (scanf("%d%d", &it->first, &it->second) != 2) {
std::abort();
}
assert(it->second > 0);
}
PointsList pointsB(N);
for (PointsList::iterator it = pointsB.begin(), endi = pointsB.end(); it != endi; ++it) {
if (scanf("%d%d", &it->first, &it->second) != 2) {
std::abort();
}
assert(it->second < 0);
}
std::sort(pointsA.begin(), pointsA.end(), cmp_by_y);
std::sort(pointsB.begin(), pointsB.end(), cmp_by_y);
const PointsList::const_iterator min_a_by_y = pointsA.begin();
const PointsList::const_iterator max_b_by_y = (pointsB.rbegin() + 1).base();
assert(*max_b_by_y == pointsB.back());
unsigned dist = manhattan_dist(*min_a_by_y, *max_b_by_y);
const unsigned diff_x = std::abs(min_a_by_y->first - max_b_by_y->first);
const unsigned best_diff_y = dist - diff_x;
const int max_y_for_a = max_b_by_y->second + dist;
const int min_y_for_b = min_a_by_y->second - dist;
PointsList::iterator it;
for (it = pointsA.begin() + 1; it != pointsA.end() && it->second <= max_y_for_a; ++it) {
}
if (it != pointsA.end()) {
pointsA.erase(it, pointsA.end());
}
PointsList::reverse_iterator rit;
for (rit = pointsB.rbegin() + 1; rit != pointsB.rend() && rit->second >= min_y_for_b; ++rit) {
}
if (rit != pointsB.rend()) {
pointsB.erase(pointsB.begin(), (rit + 1).base());
}
std::sort(pointsA.begin(), pointsA.end(), cmp_by_x);
std::sort(pointsB.begin(), pointsB.end(), cmp_by_x);
for (size_t j = 0; diff_x > 0 && j < pointsA.size(); ++j) {
const Point &cur_a_point = pointsA[j];
assert(max_y_for_a >= cur_a_point.second);
const int diff_x = dist - best_diff_y;
const int min_x = cur_a_point.first - diff_x + 1;
const int max_x = cur_a_point.first + diff_x - 1;
const Point search_term = std::make_pair(max_x, std::numeric_limits<int>::min());
PointsList::const_iterator may_be_near_it = std::lower_bound(pointsB.begin(), pointsB.end(), search_term, cmp_by_x);
for (PointsList::const_reverse_iterator rit(may_be_near_it); rit != pointsB.rend() && rit->first >= min_x; ++rit) {
const unsigned cur_dist = manhattan_dist(cur_a_point, *rit);
if (cur_dist < dist) {
dist = cur_dist;
}
}
}
printf("%u\n", dist);
}
}
$ make bench
time ./test1 < data.txt > test1_res
real 0m7.846s
user 0m7.820s
sys 0m0.000s
time ./test2 < data.txt > test2_res
real 0m0.605s
user 0m0.590s
sys 0m0.010s
for(int i = 0; i < n ;i++) {
if (pointsA[i].nd > dist)
continue; // <- this is the big one
for(int j = 0; j < n ; j++) {
if (pointsB[j].nd < -dist)
continue; // <- helps although not as much
if(abs(pointsA[i].st - pointsB[j].st) + abs(pointsA[i].nd - pointsB[j].nd) < dist) {
dist = abs(pointsA[i].st - pointsB[j].st) + abs(pointsA[i].nd - pointsB[j].nd);
}
}
printf("%lld\n", dist);
}