码迷,mamicode.com
首页 > 其他好文 > 详细

旋转卡壳

时间:2019-01-01 23:58:39      阅读:290      评论:0      收藏:0      [点我收藏+]

标签:amp   lin   efi   std   namespace   opera   als   for   ret   

题解:

大致就是先求出凸包

然后有一个性质就是我们枚举每条边

然后凸包上的点到边的距离是单峰函数(刚开始傻逼的写了点对点)

于是可以two-point-two

为什么是对的呢

因为对于最远点对

我们取一条平行于边的直线,那这条边到那个点的距离就是最远距离

所以这样就是对的

另外我发现求凸包的代码需要判重。。

不过网上好多代码都不判重。。这样有重复点的话是错的

代码:

#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cmath>
using namespace std;
#define rint register int
#define IL inline
#define ll long long
#define rep(i,h,t) for (int i=h;i<=t;i++)
#define dep(i,t,h) for (int i=t;i>=h;i--)
const int N=4e5;
struct point{
  int a,b,r;
  bool operator ==(point o)
  {
    return a==o.a&&b==o.b;
  }
  IL void jsr()
  {
    r=atan2(b,a);
  }
  point operator -(point o)
  {
    return (point){a-o.a,b-o.b};
  }
  point operator +(point o)
  {
    return (point){a+o.a,b+o.b};
  }
  int operator *(point o)
  {
    return a*o.a+b*o.b;
  } 
  int operator ^(point o)
  {
    return a*o.b-b*o.a;
  }
}p[N],q[N];
struct line{
  point a,b;
};
IL int dis(point x,point y)
{
  return (x.a-y.a)*(x.a-y.a)+(x.b-y.b)*(x.b-y.b);
}
int lenth(point x)
{
  return x.a*x.a+x.b*x.b;
}
IL int dis(point x,point y,point z)
{
  if ((y-x)*(z-x)<=0) return dis(x,z);
  if ((x-y)*(z-y)<=0) return dis(y,z);
  int l=1ll*((y-x)^(z-x))*((y-x)^(z-x))/lenth(y-x);
  return l;
}
IL bool cmp(point x,point y)
{
  return x.a<y.a||(x.a==y.a&&x.b<y.b);
}
IL bool pd(line x,point y)
{
  return (x.b^(y-x.a))<0;
}
int t,n;
void push(point x)
{
  while (1<t&&pd((line){q[t-1],q[t]-q[t-1]},x)) t--;
  q[++t]=x;
}
template<class T>void maxa(T &x,T y) {if (x<y)x=y;}
int main()
{
  freopen("1.in","r",stdin);
  freopen("1.out","w",stdout);
  ios::sync_with_stdio(false); 
  cin>>n;
  rep(i,1,n)
  {
    int x,y;
    cin>>x>>y;
    p[i]=(point){x,y};
    p[i].jsr();
  }
  sort(p+1,p+n+1,cmp);
  int m=0;
  rep(i,1,n)
    if (i==1||!(p[i]==p[i-1]))
      p[++m]=p[i];
  n=m;
  t=1;
  q[0]=q[t]=p[1];
  rep(i,2,n) 
    push(p[i]);
  dep(i,n-1,1) 
    push(p[i]);
  int k2=1;
  int ans=0;
 /* rep(i,1,t)
  {
    while (k2<t&&dis(q[i],q[k2+1])>dis(q[i],q[k2])) k2++;
    maxa(ans,dis(q[i],q[k2]));
  }*/
  rep(i,t+1,2*t) q[i]=q[i-t];
  rep(i,1,t)
  {
    while (k2<2*t&&dis(q[i],q[i+1],q[k2])<=dis(q[i],q[i+1],q[k2+1])) k2++;
    maxa(ans,dis(q[i],q[k2]));
    maxa(ans,dis(q[i+1],q[k2])); 
  }
  printf("%d",ans);
  return 0;
}

 

旋转卡壳

标签:amp   lin   efi   std   namespace   opera   als   for   ret   

原文地址:https://www.cnblogs.com/yinwuxiao/p/10206348.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!