一起来看流星雨 解题报告
这个题目其实就是求一个最远点对,然后在求最小的最远点对距离,对于求最远点对的问题,我们显然可以用旋转卡壳来做,即先求出所给流星坐标点所形成的凸包,很明显最远的点对只能出现在凸包上,求出凸包之后,我们选择能刚好卡住凸包的两条平行线,然后根据卡住的点对来更新最大值,这样旋转一圈就可以得到最大值(即旋转卡壳算法)。我们求出最远点对之后,在去考虑最远点对在什么时刻最小,这个时候我们可以根据时刻进行三分找最小值,最后求一下最小值即可。 (暴力三分不可取,因为暴力三分复杂度O(n^2logn),显然会超时。。。所以必须采用旋转卡壳)
求凸包复杂度O(nlogn)
旋转卡壳复杂度O(n)
三分复杂度O(nlogn)
总的时间复杂度: O(nlogn^2)
额外空间复杂度: O(n)
代码:
const double eps = 1e-9;
int double_cmp(double x){
if(fabs(x) < eps) return 0;
if(x > 0) return 1;
return -1;
}
struct Point_{
double x, y, vx, vy;
int id;
Point_() {}
Point_ (double _x, double _y, int i):x(_x),y(_y),id(i) {}
bool operator <(const struct Point_ &tmp)const {
if(double_cmp(x-tmp.x) == 0) return double_cmp(y-tmp.y) < 0;
return double_cmp(x-tmp.x) < 0;
}
bool operator == (const struct Point_ &tmp)const {
return double_cmp(x-tmp.x)==0&&double_cmp(y-tmp.y)==0;
}
} a[10005],st[10005],b[10005];
double XMulti(Point_ a, Point_ b, Point_ c)///ac X ab
{
return (c.x-a.x)*(b.y-a.y) - (b.x-a.x)*(c.y-a.y);
}
double dis(Point_ a, Point_ b){
return sqrt((a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y));
}
double dot(Point_ a, Point_ b, Point_ c)///点积 ab . ac
{
double s1 = b.x-a.x;
double t1 = b.y-a.y;
double s2 = c.x-a.x;
double t2 = c.y-a.y;
return s1*s2 + t1*t2;
}
int ConvexHull(Point_ *p, int n, Point_ *st)//凸包
{
sort(p, p+n);
n = unique(p, p+n)-p;//去重
int m = 0;
for(int i=0; i<n; i++) {
while(m>1 && XMulti(st[m-2],p[i],st[m-1])<=0)
m--;
st[m++] = p[i];
}
int k = m;
for(int i=n-2; i>=0; i--) {
while(m>k && XMulti(st[m-2],p[i],st[m-1])<=0)
m--;
st[m++] = p[i];
}
if(n > 1) m--;
return m;
}
double rotating_calipers(Point_ *p, int n)//旋转卡壳求凸包的直径,平面最远的点对
{
int k=1;
double ans = 0;
p[n]=p[0];
for(int i=0; i<n; i++) {
while(fabs(XMulti(p[i+1],p[k],p[i]))<fabs(XMulti(p[i+1],p[k+1],p[i])))
k=(k+1)%n;
ans = max(ans,max(dis(p[i],p[k]),dis(p[i+1],p[k])));
}
return ans;
}
int n, m;
double f(double t){
for(int i=0; i<n; i++){
b[i].x = a[i].x+t*a[i].vx;
b[i].y = a[i].y+t*a[i].vy;
}
m = ConvexHull(b, n, st);
double mx = rotating_calipers(st, m);
return mx;
}
double sanfen(double l, double r){
double midl, midr;
while(r-l>eps){
midl = l+(r-l)/3;
midr = r-(r-l)/3;
if(f(midl) >= f(midr)) l = midl;
else r = midr;
}
return midl;
}
class Solution {
public:
/**
*
* @param n int整型 流星个数
* @param star int整型vector<vector<>> 流星坐标点和速度向量
* @return double浮点型
*/
double solve(int nn, vector<vector<int> >& star) {
// write code here
n = nn;
for(int i=0; i<n; i++) {
a[i].x = star[i][0];
a[i].y = star[i][1];
a[i].vx = star[i][2];
a[i].vy = star[i][3];
}
double ans = sanfen(0, 1000000);
return f(ans);
}
};
