凸包旋转卡壳

难炸天的一道省选MODE题


所谓旋转卡壳就是求凸包的一对对踵点。
思路:1.先打基本差点乘公式;
2.排除部分点并求出凸包;
3.进行旋转卡壳(方法:假设最远两点并作出两条平行线,旋转其中一条平行线并使之与凸包的一条边重合,再求出对面点到这条边两点距离(视作三角形的高并用向量叉乘计算)的最大值,再将这条线进行逆时针旋转并重复上述过程)。
以下为有点难懂的参考代码:

#include
using namespace std;
const int N=5e4+10;
const double eps=1e-8;

inline int re()
{
	int i=0,f=1;
	char ch;
	for(ch=getchar();!isdigit(ch)&&ch!='-';ch=getchar());
	if(ch=='-')
	{
		f=-1;
		ch=getchar();
	}
	for(;isdigit(ch);ch=getchar())
	i=(i<<3)+(i<<1)+ch-48;
	return i*f;
}

int sgn(double x)
{
	if(fabs(x)<eps) return 0;
	else if(x<0) return -1;
	else return 1;
}
struct Point
{
	int x,y;
	Point(){}
	Point(int x,int y):x(x),y(y){}
	Point operator -(const Point& b)const {return Point(x-b.x,y-b.y);}//相减
	int operator ^(const Point& b)const{return x*b.y-y*b.x;}//叉乘 
	int operator *(const Point& b)const{return x*b.x+y*b.y;}//点乘 	
}ps[N],st[N];
int n,pos,top;
int x;
bool cmp(const Point& a,const Point& b)
{
	x=(a-ps[0])^(b-ps[0]);
	if(x=0)
	{
		if(a.y==b.y)
			return a.x<b.x;
		else return a.y<b.y;
	}
	else if(x>0) return 1;
	else return 0;
}
bool check(Point a,Point b,Point c)
{
	x=(b-a)^(c-a);
	return x<=0;
}
void getconv()//求凸包 
{
	st[0]=ps[0];
	st[1]=ps[1];
	top=1;
	for(int i=2;i<n;i++)
	{
		//逆时针必须向左转 
		while(top>1&&check(st[top-1],st[top],ps[i])) 
			top--;			
		st[++top]=ps[i];
	}	
} 
int dis(Point a,Point b)
{
	return (a-b)*(a-b);
}
int RC()//旋转卡壳
{
 
	if(top==1) return dis(st[0],st[1]);
	int ans=0;
	int j=2;
	st[++top]=st[0];
	for(int i=0;i<top;i++)
	{
		//找距离边最远的点 
		while(((st[i]-st[j])^(st[i+1]-st[j]))<((st[i]-st[j+1])^(st[i+1]-st[j+1])))
		j=(j+1)%top;
		//点对为其一 
		ans=max(ans,max(dis(st[i],st[j]),dis(st[i+1],st[j])));	
	}
	return ans;
} 
int main(void)
{
	scanf("%d",&n);
	pos=0;		
	for(int i=0;i<n;i++)
	{
		ps[i].x=re(),ps[i].y=re();
		if(ps[i].y<ps[pos].y || (ps[i].y==ps[pos].y&&ps[i].x<ps[pos].x))
		pos=i;
	}
	swap(ps[0],ps[pos]);
	sort(ps+1,ps+n,cmp);
	getconv();
	printf("%d\n",RC());
	return 0;
}

本蒟蒻表示此题巨难。。。。。

你可能感兴趣的:(计算几何,程序设计)