http://acm.uestc.edu.cn/problem.php?pid=1560
会升让我看的题。给你一个凸包,和凸包外一点,让找到一条射线把这个凸包分成面积相等的两块,求这个射线的单位向量。
话说,以前见过类似的,求切割成两个相等面积的。会升说枚举弧度,我的第一反应也是这个,写了好长好长,我用二分找的。结果一直WA。后来会升说可以枚举线段长,就是从射线的端点的凸包张角最大的那两个点,然后枚举线段上的点,二分即可,因为枚举弧度的话,会用到三角函数,而这个是很很损失精度的行为 = =。然后晚上吃饭回来就写差不多了,但是一直WA。想到一个BUG,因为我找两个端点是用向量找的,所以,如果两端的两个点正好一个在第二象限,一个在第三象限,那么用向量排(atan值)是不对的!改了下,用极角排序,就是用叉积排,然后就过了!!!!激动死了都!!这题比赛貌似就6个人过也。。。
至于找线段上的点使得射线切割成两个相等面积,直接找到点后利用半平面交,二分查找这个点。如果这条射线左边的凸包面积比凸包面积一半大,那么肯定要右移,就这么二分查找。
附自己做的数据两组
3 7 0 -2 1 -1 2 0 2 2 0 5 -1 5 -1 0 3 0 7 0 -2 1 -1 2 0 2 2 0 5 -1 5 -1 0 -3 0 ans: -0.8575 0.5145 0.0513 0.9987
#include <cmath> #include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <stack> #include <climits> #include <iomanip> using namespace std; const int MAX = 105; struct point {double x,y;int ind;}; struct line{point a,b; double ang;}; point p[MAX],s[MAX],c; line ln[MAX],deq[MAX],ltmp[MAX];; const double eps = 1e-6; 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); } void makeline_hp(point a,point b,line &l) // 线段(向量ab)左侧区域有效 { l.a = a; l.b = b; l.ang = atan2(a.y - b.y,a.x - b.x); // 如果是右侧区域,改成b.y - a.y,b.x - a.x } double area_polygon(point p[],int n) { if( n < 3 ) return 0.0; double s = 0.0; for(int i=0; i<n; i++) s += p[(i+1)%n].y * p[i].x - p[(i+1)%n].x * p[i].y; return fabs(s)/2.0; } bool parallel(line u,line v) { return dd( (u.a.x - u.b.x)*(v.a.y - v.b.y) - (v.a.x - v.b.x)*(u.a.y - u.b.y) , 0.0 ); } point l2l_inst_p(line l1,line l2) { point ans = l1.a; double t = ((l1.a.x - l2.a.x)*(l2.a.y - l2.b.y) - (l1.a.y - l2.a.y)*(l2.a.x - l2.b.x))/ ((l1.a.x - l1.b.x)*(l2.a.y - l2.b.y) - (l1.a.y - l1.b.y)*(l2.a.x - l2.b.x)); ans.x += (l1.b.x - l1.a.x)*t; ans.y += (l1.b.y - l1.a.y)*t; return ans; } bool equal_ang(line a,line b) // 第一次unique的比较函数 { return dd(a.ang,b.ang); } bool cmphp(line a,line b) // 排序的比较函数 { if( dd(a.ang,b.ang) ) return xy(crossProduct(b.a,b.b,a.a),0.0); return xy(a.ang,b.ang); } bool equal_p(point a,point b)//第二次unique的比较函数 { return dd(a.x,b.x) && dd(a.y,b.y); } void makeline_hp(double x1,double y1,double x2,double y2,line &l) { l.a.x = x1; l.a.y = y1; l.b.x = x2; l.b.y = y2; l.ang = atan2(y2 - y1,x2 - x1); } void inst_hp_nlogn(line *ln,int n,point *s,int &len) { len = 0; sort(ln,ln+n,cmphp); n = unique(ln,ln+n,equal_ang) - ln; int bot = 0,top = 1; deq[0] = ln[0]; deq[1] = ln[1]; for(int i=2; i<n; i++) { if( parallel(deq[top],deq[top-1]) || parallel(deq[bot],deq[bot+1]) ) return ; while( bot < top && dy(crossProduct(ln[i].a,ln[i].b, l2l_inst_p(deq[top],deq[top-1])),0.0) ) top--; while( bot < top && dy(crossProduct(ln[i].a,ln[i].b, l2l_inst_p(deq[bot],deq[bot+1])),0.0) ) bot++; deq[++top] = ln[i]; } while( bot < top && dy(crossProduct(deq[bot].a,deq[bot].b, l2l_inst_p(deq[top],deq[top-1])),0.0) ) top--; while( bot < top && dy(crossProduct(deq[top].a,deq[top].b, l2l_inst_p(deq[bot],deq[bot+1])),0.0) ) bot++; if( top <= bot + 1 ) return ; for(int i=bot; i<top; i++) s[len++] = l2l_inst_p(deq[i],deq[i+1]); if( bot < top + 1 ) s[len++] = l2l_inst_p(deq[bot],deq[top]); len = unique(s,s+len,equal_p) - s; } double disp2p(point a,point b) // a b 两点之间的距离 { return sqrt( ( a.x - b.x ) * ( a.x - b.x ) + ( a.y - b.y ) * ( a.y - b.y ) ); } bool cmp1(point a,point b) // 排序 { double len = crossProduct(c,a,b); if( dd(len,0.0) ) return xy(disp2p(c,a),disp2p(c,b)); return xy(len,0.0); } int main() { int ncases,n,len; point d,b,e,mid;; scanf("%d",&ncases); int ind = 1; while( ncases-- ) { scanf("%d",&n); for(int i=0; i<n; i++) { scanf("%lf%lf",&p[i].x,&p[i].y); p[i].ind = i; } p[n] = p[0]; for(int i=0; i<n; i++) makeline_hp(p[i],p[i+1],ln[i]); scanf("%lf%lf",&c.x,&c.y); memcpy(s,p,sizeof(p)); sort(s,s+n,cmp1); double asum = area_polygon(p,n)/2; memcpy(ltmp,ln,sizeof(ln)); b = p[s[0].ind]; e = p[s[n-1].ind]; while( !(dd(b.x,e.x) && dd(b.y,e.y)) ) { mid.x = (b.x + e.x)/2; mid.y = (b.y + e.y)/2; memcpy(ln,ltmp,sizeof(ltmp)); makeline_hp(c,mid,ln[n]); inst_hp_nlogn(ln,n+1,s,len); double al = area_polygon(s,len); if( dd(al,asum) ) break; if( dy(al,asum) ) b = mid; else e = mid; } double x = atan2(mid.y - c.y,mid.x - c.x); point ans; ans.x = cos(x); ans.y = sin(x); printf("Case #%d: ",ind++); printf("%.4lf %.4lf\n",ans.x,ans.y); } return 0; }