凸包+旋转卡壳法
题目:poj2187
寻找最远点对距离
#include<bits/stdc++.h>
using namespace std;
int n;
double eps=1e-10;
double add(double a,double b){//考虑精度的求和
if(abs(a+b)<eps*(abs(a)+abs(b))) return 0;//小于精度就是0
return a+b;//否则正常加,其实就多了上面一句,对个和要有精度判断
}
struct p{
double x,y; //坐标
p(){} //空构造器
p(double x,double y):x(x),y(y){}//构造器重载
p operator + (p pp){return p(add(x,pp.x),add(y,pp.y));} //+
p operator - (p pp){return p(add(x,-pp.x),add(y,-pp.y));} //-
p operator * (double d){return p(x*d,y*d);} //线乘
double dot(p pp){return add(x*pp.x,y*pp.y);} //叉乘
double det(p pp){return add(x*pp.y,-y*pp.x);} //点乘
};
p ps[100];//开一个点数组
bool cmp_x(const p& pp,const p&qq){//比较函数
if(pp.x!=qq.x)return pp.x<qq.x;//X坐标小的优先
return pp.y<qq.y;//然后就是Y小的优先
}
vector<p> convex_hull(p* ps,int n){//求凸包,传入数组及数量,传出向量
sort(ps,ps+n,cmp_x);//先由左到右排序,同X则由下到上
int k=0;//K个点初始化为0
vector<p> qs(n*2);//这就是处理后的数组,先开两倍,因为Kl扫两轮可能会
for(int i=0;i<n;i++){//扫一次N个点得到下半轮廓
while(k>1&&(qs[k-1]-qs[k-2]).det(ps[i]-qs[k-1])<=0) k--;//
qs[k++]=ps[i];//压入去
}
for(int i=n-2,t=k;i>=0;i--){//再扫回来得到上半轮廓
while(k>t&&(qs[k-1]-qs[k-2]).det(ps[i]-qs[k-1])<=0) k--;
qs[k++]=ps[i];//压入去
} //注意最后K++会多了一
qs.resize(k-1); //所以把长度缩一就是最终的长度了
return qs;
}
double dist(p pp,p qq){ //求距离
return (pp-qq).dot(pp-qq); //其实这里是方和
}
void solve(){
cin>>n;//输入N
for(int i=0;i<n;i++)cin>>ps[i].x>>ps[i].y; //输入N个点
vector<p> qs=convex_hull(ps,n);//执行凸包,删去内部点
int n=qs.size(); //得到新的凸包点集的点数
if(n==2){ //只果只有两个点
printf("%.0f\n",dist(qs[0],qs[1])); //输出
return ;
}
int i=0,j=0; //开始旋转卡壳法
for(int k=0;k<n;k++{ //先把全部点扫一次
if(!cmp_x(qs[i],qs[k]))i=k; //I是横坐标最右的点,有多个则上者
if(cmp_x(qs[j],qs[k]))j=k; //J是横坐标最左的点,有多个则取下者
}
double res=0;//初始化答案
int si=i,sj=j;//初始化两个扫描点
while(i!=sj||j!=si){//直到两个扫描点互换位置(差不多就是都扫了180度的样子)
res=max(res,dist(qs[i],qs[j]));
if((qs[(i+1)%n]-qs[i]).det(qs[(j+1)%n]-qs[j])<0)//叉乘判断谁哪个旋转点旋转
i=(i+1)%n; //I移到下一个点
else j=(j+1)%n; //J移到下一个点
}//上面的判断要用数学方法解释:叉乘的值与旋转角度的关系
printf("%.0f\n",res);//输出答案
}
int main(){
solve();
return 0;
}
/*
Input output
8 80
0 5
1 8
3 4
5 0
6 2
6 6
8 3
8 7
补充:关于空间中求点距
两点间距离有三种:欧几/曼哈/MAX(X,Y)距离
询问可以是求空间中一点,令其到所有点的距离最大值最小,或距离的和最小
思路:三分套三分,三维套三重
向量
A X B 大于0 A在B顺时针方向
A X B 小于0 A在B逆时针方向
A X B 等于0 AB共线方向不定
#define eps 1e-8
int sgn(double x)
{
if(fabs(x)<eps)return 0;
if(x<0)return -1;
else return 1;
}
*/