2016級算法第六次上機-E.Bamboo之吃我一拳
阿新 • • 發佈:2018-01-03
查找 algo sca 一次 所有 block pre 分析 log
最近點對的距離d要麽是某次遞歸找到的d‘,要麽是左邊右邊各取一個點組成的點對。就要查找是否存在距離小於d‘且一個在左一個在右的點對。如果這兩個點的距離<d‘,那麽兩個點其實都各自在距離垂直線d‘的距離之內。也就是以垂直線為軸線,寬度為2*d‘的範圍內,將這個範圍內的點取出,並按照Y升序排列,只需要遍歷任一點與範圍內周圍7個點的距離就可以了,比較選擇更小值。
Bamboo之吃我一拳
分析
當兩個點的距離<=d時,才可以出拳,想要使得滿足出拳條件的點對最少但不為0
尋找最近點對距離,得到的最近距離能夠使得可以出拳的組數最少,因為除了最近點對外其他組合均不符合條件。
在一堆點中找到兩個點的距離最小,暴力的O(n^2)計算量很恐怖,可以用分治思想把問題變小:
把平面上的點分為兩撥,距離最近的兩個點只可能出現在:第一堆,第二堆,和兩堆2中各自一個點
分解
想象一條垂直線把所給點集分成兩撥:所有的點要麽在直線左邊,要麽在其右邊。按x坐標升序排列。
解決
劃分後兩次遞歸調用,一次找到左邊中的最近點對,一次找右邊中的最近點對。取d‘為兩者中的最小值
合並
最近點對的距離d要麽是某次遞歸找到的d‘,要麽是左邊右邊各取一個點組成的點對。就要查找是否存在距離小於d‘且一個在左一個在右的點對。如果這兩個點的距離<d‘,那麽兩個點其實都各自在距離垂直線d‘的距離之內。也就是以垂直線為軸線,寬度為2*d‘的範圍內,將這個範圍內的點取出,並按照Y升序排列,只需要遍歷任一點與範圍內周圍7個點的距離就可以了,比較選擇更小值。
代碼
#include <iostream>
#include <algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<string>
#include<iomanip>
using namespace std;
const int maxx = 1e5 + 3;
int num[maxx];
struct point{
int x, y;
}p[maxx];
bool cmpx(const point&a, const point& b)//按x坐標排序
{
return a.x<b.x;
}
bool cmpy(const int& a, const int &b)//按y坐標排序
{
return p[a].y<p[b].y;
}
double dis(point a, point b)//計算兩點距離
{
return ((double)(a.x - b.x)*(a.x - b.x) + (double)(a.y - b.y)*(a.y - b.y));
}
double closest(int low, int high)//求最近距離
{
if (low + 1 == high)//兩個點情況,已經遞歸到底
return dis(p[low], p[high]);
if (low + 2 == high)//三個點
return min(dis(p[low], p[high]), min(dis(p[low], p[low + 1]), dis(p[low + 1], p[high])));
int mid = (low + high) / 2;
double ans = min(closest(low, mid), closest(mid + 1, high));//兩組分別遞歸,去最下者
int i, j, cnt = 0;
for (i = low; i <= high; i++)
{
if (p[i].x >= p[mid].x - ans && p[i].x <= p[mid].x + ans)
num[cnt++] = i;
}
sort(num, num + cnt, cmpy);//這是在直線兩側ans距離內的點按y坐標排序
for (i = 0; i < cnt; i++) {
int k = i + 7 > cnt ? cnt : i + 7;
for (j = i + 1; j < k; j++) {
if (p[num[j]].y - p[num[i]].y > ans)
break;
ans = min(dis(p[num[i]], p[num[j]]), ans);
}
}
return ans;
}
int main()
{
int n;
while (~scanf("%d", &n))
{
for (int i = 0; i<n; i++)
scanf("%d %d", &p[i].x, &p[i].y);
sort(p, p + n, cmpx);
double ans = closest(0, n - 1);
ans = sqrt(ans);
printf("%.2lf\n", ans);
}
}
另外
嚴格的說本題的數據是要卡掉O(n^2)暴力算法的,但你們的grh大佬借助sin 和cos計算距離,運算時間甚至比O(nlogn)的分治法還要快,,,
2016級算法第六次上機-E.Bamboo之吃我一拳