BZOJ 2618 [Cqoi2006]凸多边形

来源:互联网 发布:微信支付接口开发 php 编辑:程序博客网 时间:2024/06/11 20:23

半平面交

裸的,注意事项在代码里。

#include<cmath>#include<cstdio>#include<cstdlib>#include<algorithm>#define N 505using namespace std;namespace runzhe2000{    typedef double db;    const db eps = 1e-5;    struct point    {        db x, y;        point operator + (const point &that) const {return (point){x + that.x, y + that.y};}        point operator - (const point &that) const {return (point){x - that.x, y - that.y};}        db operator * (const point &that) const {return x*that.y-y*that.x;}        point operator * (const db &v) const {return (point){x*v, y*v};}    }p[N];    struct line    {        point p, v; db alpha;        bool operator < (const line &that) const {return alpha < that.alpha;}    }l[N], q[N];    int n, lcnt, head, tail;    point get_cp(line l1, line l2)    {        /*            精妙的实现。考虑通过面积比得到高的比,再得到线段的比。注意叉乘别反了。         */         point u = l1.p - l2.p; db base = (l2.v * u) / (l1.v * l2.v);        return l1.p + l1.v * base;    }    bool onlef(point p, line l)    {        point u = p-l.p; return l.v * u > 0;    }    void HP()    {        sort(l+1, l+1+lcnt);         for(int i = 1; i <= lcnt; i++)        {            for(; tail - head >= 2 && !onlef(get_cp(q[tail-1], q[tail-2]), l[i]); tail--);            if(tail - head >= 1 && fabs(l[i].alpha - q[tail-1].alpha) < eps) q[tail-1] = onlef(q[tail-1].p, l[i]) ? q[tail-1] : l[i]; // 考虑直线的斜率相等             else q[tail++] = l[i];        }        for(;tail-head>2;) //把头尾多余的半平面不断删除掉         {            if(!onlef(get_cp(q[head], q[head+1]), q[tail-1])) head++;            else if(!onlef(get_cp(q[tail-1], q[tail-2]), q[head])) tail--;            else break;        }        if(tail-head <= 2) {puts("0.000\n");exit(0);}        /*            无解当且仅当做到某一个半平面时,该半平面与之前的半平面交产生矛盾,那此时一定已经至少转了180度,因而这时候把这些半平面交出队之后不可能围成无界图形。             因为这题保证了围成的面积是有界的,所以可以直接通过判无界来判断无解。            对于更一般的图,解不一定是有界的,也许可以采用在外面套上一圈巨大的半平面来制约它,强行有界。         */     }    void main()    {        scanf("%d",&n);        for(int i = 1; i <= n; i++)        {            int cnt; scanf("%d",&cnt);            for(int j = 1; j <= cnt; j++) scanf("%lf%lf",&p[j].x,&p[j].y); p[cnt+1] = p[1];            for(int j = 1; j <= cnt; j++) ++lcnt, l[lcnt].p = p[j], l[lcnt].v = p[j+1] - p[j], l[lcnt].alpha = atan2(l[lcnt].v.y, l[lcnt].v.x);        }        HP(); q[tail] = q[head]; int cnt = 0;        for(int i = head; i < tail; i++) p[++cnt] = get_cp(q[i], q[i+1]);        p[cnt+1] = p[1];        db ans = 0; for(int i = 1; i <= cnt; i++) ans += p[i] * p[i+1];        printf("%.3lf\n",ans/2);    }}int main(){     runzhe2000::main();}

UPD(20170715):复习一下,再敲一遍,注释里是新的理解

#include<cstdio>#include<cmath>#include<algorithm>#define N 505using namespace std;namespace runzhe2000{    typedef double db;    const db eps = 1e-7, inf = 1e9;    struct point    {        db x, y;        db operator * (const point &that) const {return x*that.y-y*that.x;}        point operator - (const point &that) const {return (point){x-that.x, y-that.y};}        point operator + (const point &that) const {return (point){x+that.x, y+that.y};}        point operator * (db v) const {return (point){x*v, y*v};}    }p[N];    struct line    {        point p, v;        db deg;        bool operator < (const line &that) const         {            return fabs(deg - that.deg) < eps ? (that.p-p)*v > 0 : deg < that.deg;        }    }l[N], q[N];    point get_cp(line a, line b)    {        point u = a.p - b.p; db v = b.v * u / (a.v * b.v);        return a.p + a.v*v;         }    bool onlef(point p, line l)    {        return l.v*(p-l.p) > 0;    }    int n, cnt;    void main()    {        scanf("%d",&n);        for(int i = 1; i <= n; i++)        {            int m; scanf("%d",&m);            for(int j = 1; j <= m; j++)                scanf("%lf%lf",&p[j].x,&p[j].y);            p[m+1] = p[1];            for(int j = 1; j <= m; j++)            {                l[++cnt].p = p[j];                l[cnt].v = p[j+1] - p[j];                l[cnt].deg = atan2(l[cnt].v.y, l[cnt].v.x);            }        }        l[++cnt].p = (point){ inf,  inf}, l[cnt].v = (point){-inf, 0}, l[cnt].deg = atan2(l[cnt].v.y, l[cnt].v.x);        l[++cnt].p = (point){ inf, -inf}, l[cnt].v = (point){0,  inf}, l[cnt].deg = atan2(l[cnt].v.y, l[cnt].v.x);        l[++cnt].p = (point){-inf,  inf}, l[cnt].v = (point){0, -inf}, l[cnt].deg = atan2(l[cnt].v.y, l[cnt].v.x);        l[++cnt].p = (point){-inf, -inf}, l[cnt].v = (point){ inf, 0}, l[cnt].deg = atan2(l[cnt].v.y, l[cnt].v.x);        /*            增加大边界,虽然这题并不一定要加。        */        sort(l+1, l+1+cnt); int tmp = 1;        for(int i = 2; i <= cnt; i++)            if(fabs(l[i].deg - l[tmp].deg) > eps) l[++tmp] = l[i];        cnt = tmp;        /*            去掉斜率相等的直线,以防有问题。        */        q[0] = l[1], q[1] = l[2]; int head = 0, tail = 2;        for(int i = 3; i <= cnt; i++)        {            for(; tail - head >= 2 && !onlef(get_cp(q[tail-1], q[tail-2]), l[i]); tail--);            q[tail++] = l[i];        }               for(; tail - head > 2; )        {            if(!onlef(get_cp(q[tail-1], q[tail-2]), q[head])) tail--;            else if(!onlef(get_cp(q[head], q[head+1]), q[tail-1])) head++;            else break;        }        if(tail - head <= 2) puts("0.000");        /*            无解当且仅当做到某一个半平面时,该半平面与之前的半平面交产生矛盾,那此时一定已经至少转了180度,因而这时候把这些半平面交出队之后不可能围成无界图形。             因为这题保证了围成的面积是有界的,所以可以直接通过判无界来判断无解。对于更一般的图,解不一定是有界的,也许可以采用在外面套上一圈大半平面来制约它,强行有界。            至于为什么只需要判断队列里是否只剩2个以下的半平面,而不存在多个(>2)半平面围出一个无界半平面的情况。不知道,想了半天也不会证。        */        else        {            int c = 0; q[tail] = q[head];            for(int i = head; i < tail; i++) p[++c] = get_cp(q[i], q[i+1]);            p[0] = p[c]; db ans = 0;            for(int i = 1; i <= c; i++) ans += p[i-1]*p[i];            printf("%.3lf\n",ans/2);        }    }}int main(){    runzhe2000::main();}
0 0
原创粉丝点击