UVA 11626 Convex Hull

凸包。。。我要刷光各大OJ的凸包。。。

 

从discuss学来的。。。刚开始没看懂题意都。。想麻烦了。。

 

这个题是给你凸包上的点,给的无序,让你排出来有序的。

 

这个方法遇到一种情况就坏了。。。

 

就是下图:

UVA 11626 Convex Hull_第1张图片

 

但是,对于凸包来说,一定能找到一个点,过这个点平行于Y轴或者X轴的直线 能划分成两个区域。

 

不过具体怎么求,还要想想。

 

这道题是直接告诉你了,按x最小的去求。

 

 

 

 

啊。。不对。。这题应该是数据弱了。。这么做是不对滴。。。上面的图就是反例啊。。。

 

我试试另一种做法~刚想起来~

 

下面这个代码是很弱的。。。看下个代码吧~^ ^

 

#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> using namespace std; const int MAX = 100010; struct point{ int x,y; }; point c[MAX]; int m; long long crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 { return (c.x - a.x*1ll)*(b.y - a.y) - (b.x - a.x*1ll)*(c.y - a.y); } long long disp2p(point a,point b) { return ( a.x - b.x*1ll ) * ( a.x - b.x ) + ( a.y - b.y*1ll ) * ( a.y - b.y ); } bool cmp1(point a,point b) // 排序 { long long len = crossProduct(c[0],a,b); if( len == 0 ) return disp2p(c[0],a) < disp2p(c[0],b); return len < 0; } bool cmp2(point a,point b) { long long len = crossProduct(c[0],a,b); if( len == 0 ) return disp2p(c[0],a) > disp2p(c[0],b); return len < 0; } void output(point *p,int n) { for(int i=0; i<n; i++) printf("%d %d/n",p[i].x,p[i].y); } void solve() { int tmp = 0; for(int i=1; i<m; i++) if( c[i].x < c[tmp].x || c[i].x == c[tmp].x && c[i].y < c[tmp].y ) tmp = i; swap(c[0],c[tmp]); point L[MAX],U[MAX]; int l = 0,u = 0; for(int i=1; i<m; i++) if( c[i].y <= c[0].y ) L[l++] = c[i]; else U[u++] = c[i]; sort(L,L+l,cmp1); sort(U,U+u,cmp2); printf("%d/n",m); printf("%d %d/n",c[0].x,c[0].y); output(L,l); output(U,u); } int main() { int ncases,n; int x,y; char ch; scanf("%d",&ncases); while( ncases-- ) { scanf("%d",&n); m = 0; for(int i=0; i<n; i++) { scanf("%d %d %c",&x,&y,&ch); if( ch == 'Y' ) { c[m].x = x; c[m++].y = y; } } solve(); } return 0; }  

 

 

 

 

昨晚失眠了,3点半的时候床上躺了会,迷迷瞪瞪地,四点被姐的飞信吵醒了 = =。。迟钝死了都。突然想起来怎么划分这题了。

 

直接找最远点对,然后这个点对分成的凸包的两个区域再按照上面的排序,就OK了。。。

 

然后下床实现~排除各种BUG。。A掉了,时间和上个差不多。都是N*LOGN的~~

 

#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> using namespace std; const int MAX = 100010; struct point{ int x,y; }; point c[MAX]; int stk[MAX],top; int m; long long crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 { return (c.x - a.x*1ll)*(b.y - a.y) - (b.x - a.x*1ll)*(c.y - a.y); } long long disp2p(point a,point b) { return ( a.x - b.x*1ll ) * ( a.x - b.x ) + ( a.y - b.y*1ll ) * ( a.y - b.y ); } bool cmp1(point a,point b) // 排序 { long long len = crossProduct(c[0],a,b); if( len == 0 ) return disp2p(c[0],a) < disp2p(c[0],b); return len < 0; } bool cmp2(point a,point b) { long long len = crossProduct(c[0],a,b); if( len == 0 ) return disp2p(c[0],a) > disp2p(c[0],b); return len < 0; } int Left,Right; void Rotating_calipers(int stk[],int n) { stk[n] = stk[0]; int q = 1; long long ans = 0ll; int a,b; for(int i=0; i<n; i++) { while( crossProduct(c[stk[i]],c[stk[i+1]],c[stk[q]]) < crossProduct(c[stk[i]],c[stk[i+1]],c[stk[q+1]]) ) q = (q+1)%n; if( disp2p(c[stk[i]],c[stk[q]]) > ans ) { ans = disp2p(c[stk[i]],c[stk[q]]); a = stk[i]; b = stk[q]; } } if( c[a].x < c[b].x || c[a].x == c[b].x && c[a].y < c[b].y ) { Left = a; Right = b; } else { Left = b; Right = a; } } void Graham(int n) { int tmp = 0; for(int i=1; i<n; i++) if( c[i].x < c[tmp].x || c[i].x == c[tmp].x && c[i].y < c[tmp].y ) tmp = i; swap(c[0],c[tmp]); sort(c+1,c+n,cmp1); stk[0] = 0; stk[1] = 1; top = 1; for(int i=2; i<n; i++) { while( crossProduct(c[stk[top]],c[stk[top-1]],c[i]) <= 0ll && top >= 1 ) top--; stk[++top] = i; } Rotating_calipers(stk,top+1); } vector<point> p; void solve() { Graham(m); point L[MAX],U[MAX]; int l = 0,u = 0; for(int i=0; i<m; i++) { if( i == Left || i == Right ) continue; if( crossProduct(c[Left],c[Right],c[i]) >= 0 ) L[l++] = c[i]; else U[u++] = c[i]; } sort(L,L+l,cmp1); sort(U,U+u,cmp2); printf("%d/n",m); p.clear(); p.push_back(c[Left]); for(int i=0; i<l; i++) p.push_back(L[i]); p.push_back(c[Right]); for(int i=0; i<u; i++) p.push_back(U[i]); int tmp = 0; for(int i=0; i<p.size(); i++) if( p[i].x < p[tmp].x || p[i].x == p[tmp].x && p[i].y < p[tmp].y ) tmp = i; int k = 0; while( k < m ) { printf("%d %d/n",p[tmp].x,p[tmp].y); tmp = (tmp+1)%m; k++; } } int main() { int ncases,n; int x,y; char ch; scanf("%d",&ncases); while( ncases-- ) { scanf("%d",&n); m = 0; for(int i=0; i<n; i++) { scanf("%d %d %c",&x,&y,&ch); if( ch == 'Y' ) { c[m].x = x; c[m++].y = y; } } solve(); } return 0; }  

 

 

好啦,第三个代码~内点排序,用重心哈,凸包的重心一定是在内部的(也不可能在边上)。

 

因为加了精度判断,慢了不少。

 

写比较函数很纠结啊。。。

 

#include <queue> #include <stack> #include <math.h> #include <stdio.h> #include <stdlib.h> #include <iostream> #include <limits.h> #include <string.h> #include <string> #include <algorithm> using namespace std; const int MAX = 100010; struct point{ double x,y; }; point c[MAX]; int m; const double eps = 1e-8; bool dy(double x,double y) { return x > y + eps;} // x > y bool xy(double x,double y) { return x < y - eps;} // x < y bool dyd(double x,double y) { return x > y - eps;} // x >= y bool xyd(double x,double y) { return x < y + eps;} // x <= y bool dd(double x,double y) { return fabs( x - y ) < eps;} // x == y // 叉积 (三点) double crossProduct(point a,point b,point c)//向量 ac 在 ab 的方向 { return (c.x - a.x)*(b.y - a.y) - (b.x - a.x)*(c.y - a.y); } point bary_center(point p[],int n) { point ans,t; double area = 0.0,t2; ans.x = 0.0; ans.y = 0.0; for(int i=1; i<n-1; i++) { t2 = crossProduct(p[i],p[0],p[i+1])/2.0; ans.x += (p[0].x + p[i].x + p[i+1].x)*t2; ans.y += (p[0].y + p[i].y + p[i+1].y)*t2; area += t2; } ans.x /= (3*area); ans.y /= (3*area); return ans; } point s; bool cmp(point a,point b) { double l1 = crossProduct(s,c[0],a); double l2 = crossProduct(s,c[0],b); if( dyd(l1,0.0) && dyd(l2,0.0) ) return xy(crossProduct(s,a,b),0.0); if( dyd(l1,0.0) && xyd(l2,0.0) ) return 0; if( xyd(l1,0.0) && xyd(l2,0.0) ) return xy(crossProduct(s,a,b),0.0); return 1; } void solve() { s = bary_center(c,m); int tmp = 0; for(int i=1; i<m; i++) if( xy(c[i].x,c[tmp].x) || dd(c[i].x,c[tmp].x) && xy(c[i].y,c[tmp].y) ) tmp = i; swap(c[tmp],c[0]); sort(c+1,c+m,cmp); printf("%d/n",m); for(int i=0; i<m; i++) printf("%.0lf %.0lf/n",c[i].x,c[i].y); } int main() { int ncases,n; double x,y; char ch; scanf("%d",&ncases); while( ncases-- ) { scanf("%d",&n); m = 0; for(int i=0; i<n; i++) { scanf("%lf %lf %c",&x,&y,&ch); if( ch == 'Y' ) { c[m].x = x; c[m++].y = y; } } solve(); } return 0; }  


你可能感兴趣的:(UVA 11626 Convex Hull)