4.1 求解平面最远点对(POJ 2187 Beauty Contest) struct Point { int x,y; Point(int _x = 0,int _y = 0) { 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; } void input() { scanf("%d%d",&x,&y); } }; //距离的平方 int dist2(Point a,Point b) { return (a-b)*(a-b); } //******二维凸包,int*********** const int MAXN = 50010; Point list[MAXN]; int Stack[MAXN],top; bool _cmp(Point p1,Point p2) { int tmp = (p1-list[0])^(p2-list[0]); if(tmp > 0)return true; else if(tmp == 0 && dist2(p1,list[0]) <= dist2(p2,list[0])) return true; else return false; } void Graham(int n) { Point p0; int k = 0; p0 = list[0]; for(int i = 1;i < n;i++) if(p0.y > list[i].y || (p0.y == list[i].y && p0.x > list[i].x)) { p0 = list[i]; k = i; } swap(list[k],list[0]); sort(list+1,list+n,_cmp); if(n == 1) { top = 1; Stack[0] = 0; return; } if(n == 2) { top = 2; Stack[0] = 0; Stack[1] = 1; return; } Stack[0] = 0; Stack[1] = 1; top = 2; for(int i = 2;i < n;i++) { while(top > 1 && ((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0) top--; Stack[top++] = i; } } //旋转卡壳,求两点间距离平方的最大值 int rotating_calipers(Point p[],int n) { int ans = 0; Point v; int cur = 1; for(int i = 0;i < n;i++) { v = p[i]-p[(i+1)%n]; while((v^(p[(cur+1)%n]-p[cur])) < 0) cur = (cur+1)%n; ans = max(ans,max(dist2(p[i],p[cur]),dist2(p[(i+1)%n],p[(cur+1)%n]))); } return ans; } Point p[MAXN]; int main() { int n; while(scanf("%d",&n) == 1) { for(int i = 0;i < n;i++)list[i].input(); Graham(n); for(int i = 0;i < top;i++)p[i] = list[Stack[i]]; printf("%d ",rotating_calipers(p,top)); } return 0; } 4.2 求解平面点集最大三角形 //旋转卡壳计算平面点集最大三角形面积 int rotating_calipers(Point p[],int n) { int ans = 0; Point v; for(int i = 0;i < n;i++) { int j = (i+1)%n; int k = (j+1)%n; while(j != i && k != i) { ans = max(ans,abs((p[j]-p[i])^(p[k]-p[i]))); while( ((p[i]-p[j])^(p[(k+1)%n]-p[k])) < 0 ) k = (k+1)%n; j = (j+1)%n; } } return ans; } Point p[MAXN]; int main() { int n; while(scanf("%d",&n) == 1) { if(n == -1)break; for(int i = 0;i < n;i++)list[i].input(); Graham(n); for(int i = 0;i < top;i++)p[i] = list[Stack[i]]; printf("%.2f ",(double)rotating_calipers(p,top)/2); } return 0; } 4.3 求解两凸包最小距离(POJ 3608) const double eps = 1e-8; int sgn(double x) { if(fabs(x) < eps)return 0; if(x < 0)return -1; else return 1; } struct Point { double x,y; Point(double _x = 0,double _y = 0) { x = _x; y = _y; } Point operator -(const Point &b)const { return Point(x - b.x, y - b.y); } double operator ^(const Point &b)const { return x*b.y - y*b.x; } double operator *(const Point &b)const { return x*b.x + y*b.y; } void input() { scanf("%lf%lf",&x,&y); } }; struct Line { Point s,e; Line(){} Line(Point _s,Point _e) { s = _s; e = _e; } }; //两点间距离 double dist(Point a,Point b) { return sqrt((a-b)*(a-b)); } //点到线段的距离,返回点到线段最近的点 Point NearestPointToLineSeg(Point P,Line L) { Point result; double t = ((P-L.s)*(L.e-L.s))/((L.e-L.s)*(L.e-L.s)); if(t >=0 && t <= 1) { result.x = L.s.x + (L.e.x - L.s.x)*t; result.y = L.s.y + (L.e.y - L.s.y)*t; } else { if(dist(P,L.s) < dist(P,L.e)) result = L.s; else result = L.e; } return result; } /* * 求凸包,Graham算法 * 点的编号0~n-1 * 返回凸包结果Stack[0~top-1]为凸包的编号 */ const int MAXN = 10010; Point list[MAXN]; int Stack[MAXN],top; //相对于list[0]的极角排序 bool _cmp(Point p1,Point p2) { double tmp = (p1-list[0])^(p2-list[0]); if(sgn(tmp) > 0)return true; else if(sgn(tmp) == 0 && sgn(dist(p1,list[0]) - dist(p2,list[0])) <= 0) return true; else return false; } void Graham(int n) { Point p0; int k = 0; p0 = list[0]; //找最下边的一个点 for(int i = 1;i < n;i++) { if( (p0.y > list[i].y) || (p0.y == list[i].y && p0.x > list[i].x) ) { p0 = list[i]; k = i; } } swap(list[k],list[0]); sort(list+1,list+n,_cmp); if(n == 1) { top = 1; Stack[0] = 0; return; } if(n == 2) { top = 2; Stack[0] = 0; Stack[1] = 1; return ; } Stack[0] = 0; Stack[1] = 1; top = 2; for(int i = 2;i < n;i++) { while(top > 1 && sgn((list[Stack[top-1]]-list[Stack[top-2]])^(list[i]-list[Stack[top-2]])) <= 0) top--; Stack[top++] = i; } } //点p0到线段p1p2的距离 double pointtoseg(Point p0,Point p1,Point p2) { return dist(p0,NearestPointToLineSeg(p0,Line(p1,p2))); } //平行线段p0p1和p2p3的距离 double dispallseg(Point p0,Point p1,Point p2,Point p3) { double ans1 = min(pointtoseg(p0,p2,p3),pointtoseg(p1,p2,p3)); double ans2 = min(pointtoseg(p2,p0,p1),pointtoseg(p3,p0,p1)); return min(ans1,ans2); } //得到向量a1a2和b1b2的位置关系 double Get_angle(Point a1,Point a2,Point b1,Point b2) { return (a2-a1)^(b1-b2); } double rotating_calipers(Point p[],int np,Point q[],int nq) { int sp = 0, sq = 0; for(int i = 0;i < np;i++) if(sgn(p[i].y - p[sp].y) < 0) sp = i; for(int i = 0;i < nq;i++) if(sgn(q[i].y - q[sq].y) > 0) sq = i; double tmp; double ans = dist(p[sp],q[sq]); for(int i = 0;i < np;i++) { while(sgn(tmp = Get_angle(p[sp],p[(sp+1)%np],q[sq],q[(sq+1)%nq])) < 0) sq = (sq+1)%nq; if(sgn(tmp) == 0) ans = min(ans,dispallseg(p[sp],p[(sp+1)%np],q[sq],q[(sq+1)%nq])); else ans = min(ans,pointtoseg(q[sq],p[sp],p[(sp+1)%np])); sp = (sp+1)%np; } return ans; } double solve(Point p[],int n,Point q[],int m) { return min(rotating_calipers(p,n,q,m),rotating_calipers(q,m,p,n)); } Point p[MAXN],q[MAXN]; int main() { int n,m; while(scanf("%d%d",&n,&m) == 2) { if(n == 0 && m == 0)break; for(int i = 0;i < n;i++) list[i].input(); Graham(n); for(int i = 0;i < top;i++) p[i] = list[i]; n = top; for(int i = 0;i < m;i++) list[i].input(); Graham(m); for(int i = 0;i < top;i++) q[i] = list[i]; m = top; printf("%.4f ",solve(p,n,q,m)); } return 0; }