计算几何-UESTC 484 Division

来源:互联网 发布:2000年人口普查数据 编辑:程序博客网 时间:2024/04/27 03:49


题意:给一个萌点,找到经过这个萌点的射线可以平分多边形。


题解:
1、遍历角度会wa,需要遍历距离。因为枚举角度的话会用到三角函数,听说会损失精度。
2、二分的时候二分五六十次不然100次就差不多了,我把精度弄成了l和r相差10的-7次方就wa了。真2。
3、如何判断两个端点是不是在边上呢?!我一开始枚举斜率,这么损失精度的方法真是蠢死了。叉积:a X b = |a||b|sinα 。也就是说a和b的角度小于180的话,叉积大于0,大于180的话,叉积小于0。最右的端点和萌点的连线和其余点和萌点的连线叉乘一定全都大于0或者共线,最左端点和萌点的连线和萌点的连线叉乘一定全部大于0或者共线。
4、注意多边形的顶点。判断是否在线段上的时候算左边点不算右边点就好了。而且还要判一下交点是不是多边形顶点。
5、总结一下。先通过叉乘不小于0找到最右端点,再通过叉乘不大于0找到最左端点,做一条线段,遍历距离。然后得到一条直线和一个多边形。
6、5之后的方法1:通过叉乘找到所有在这条线右边的顶点,加入新多边形的点集,(算上共线),找到和线段的交点加入点集(不算上端点)。
7、5之后的方法2:记录端点号,把两个交点加入点集,以及从较小端点到较大端点的所有端点序号。(注意判一下是不是交点,如果已经加进去过了就别加了)。然后看看最右端点在不在集合中。以此来判断算出的多边形面积是啥
8、6或者7之后,得到新多边形面积,如果刚好是“多边形/2”就找到了。

#include <cstdio>#include <cstring>#include <algorithm>#include <cmath>#define SIZE_N 330#define INF 0x3f3f3f3fusing namespace std;const double PI = acos(-1);const double eps = 1e-8;const double eps1 = 1e-5;int cmp(double x){    if (fabs(x)< eps) return 0;    if (x>0) return 1;    return -1;}struct point{    double x,y;    point(){}    point (double a, double b): x(a),y(b) {}    friend point operator + (const point &a, const point &b){        return point(a.x + b.x, a.y + b.y);    }    friend point operator - (const point &a,const point &b){        return point(a.x - b.x, a.y - b.y);    }    friend point operator * (const double &a, const point &b){        return point(a * b.x, a * b.y);    }    friend point operator * (const point &a, const double &b){        return point(a.x * b, a.y * b);    }    friend point operator / (const point &a, const double &b){        return point(a.x/b, a.y/b);    }    friend bool operator == (const point &a, const point &b){        return cmp(a.x-b.x) == 0 && cmp(a.y-b.y) == 0;    }}p[SIZE_N],ptemp[SIZE_N];struct line{    point a,b;}line1[SIZE_N];double l,r;//从0到1二分距离int N;int left,right;//最左边点的序号和最右边点的序号double ar;double det(const point &a,const point &b){    return a.x * b.y -a.y * b.x;}double dot(const point &a,const point &b){    return a.x * b.x + a.y *b.y;}bool PointOnSegment (point p,point s,point t){//p在st上面!    return cmp(det(p-s,t-s))== 0 && cmp(dot(p-s,p-t))<= 0;}bool parallel(line a, line b){    return !cmp(det(a.a - a.b, b.a - b.b));}bool line_make_point(line a,line b, point &res){    if (parallel(a,b)) return 0;    double s1 = det(a.a-b.a, b.b - b.a);    double s2 = det(a.b - b.a, b.b - b.a);    res = (s1 * a.b - s2 * a.a)/(s1-s2);    if(b.b == res )        return 0;    if (PointOnSegment(res,b.a,b.b))        return 1;    return 0;}int cmin,cmax;point res1,res2;double area(point a[],int n){    double sum = 0;    a[n] = a[0];    for (int i = 0; i < n; i++){        sum+= det(a[i],a[i+1]);    }    sum = fabs(sum);    return sum/2.0;}double getarea(int cmin,int cmax){    int num = 0;    ptemp[num++] = res1;    int isright = 0;    for (int i = cmin; i < cmax; i++){        ptemp[num++] = p[i];        if (i == right)            isright = 1;    }    if (!(res2 == p[cmax-1]) ){        ptemp[num++] = res2;    }    if (isright == 1)        return area(ptemp,num);    else        return ar - area(ptemp,num);}bool check(point P, point now){    line li;    li.a = P;    li.b = now;    int sum = 0;    point res;    int cmin = -1,cmax;    for (int i = 1; i <= N; i++){        if (line_make_point(li,line1[i],res)){            sum++;            if (sum == 1){                res1 = res;                cmin = i;            }            else{                res2 = res;                cmax = i;            }        }    }    if ( cmp(getarea(cmin,cmax )-(ar/2.0) )==-1)        return 1;    return 0;}double getdis(point p,point q){    return sqrt((p.y-q.y)*(p.y-q.y) + (p.x-q.x)*(p.x-q.x));}double trans(double x){    if(abs(x) < eps1) return abs(x);    else return x;}void getlr(point P){    for (int i = 0; i < N; i++){        int isr = 0,isl = 0;        for (int j = 0; j < N; j++){            if (j != i){                if (!(cmp(det(p[i]-P,p[j]-P) ) != -1))                    isr = 1;                else                    isl = 1;            }        }        if (isr != 1){            right = i;        }        if (isl != 1)left = i;    }}int main(){    //freopen("input.txt","r",stdin);    int T;    scanf("%d",&T);    int cas = 1;    while (T--){        scanf("%d",&N);        for (int i = 0; i < N; i++){            scanf("%lf %lf",&p[i].x,&p[i].y);            if (i != 0){                line1[i].a = p[i-1];                line1[i].b = p[i];            }        }ar = area(p,N);        line1[N].a = p[N-1];        line1[N].b = p[0];//从第1条线一直到第N条线        point P;        scanf("%lf %lf",&P.x,&P.y);        point pr,pl;        getlr(P);        pr = p[right];        pl = p[left];        r = 1.0;        l = 0;        double res0;        point resc;        point now;int a7 = 60;        while (a7--){            double mid = (r + l)/(2.0);            now = pl + mid * (pr-pl);            if (check(P,now)){                resc = now;                r = mid;            }else                l = mid;        }        double dis = getdis(now,P);        printf("Case #%d: %.4f %.4f\n",cas++,trans((now.x-P.x)/dis+eps),trans((now.y-P.y)/dis+eps));    }    return 0;}



0 0
原创粉丝点击