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
- BZOJ-2618-凸多边形-CQOI2006
- BZOJ 2618: [Cqoi2006]凸多边形
- BZOJ 2618 [Cqoi2006]凸多边形
- BZOJ 2618 CQOI2006 凸多边形 半平面交
- 【BZOJ 2618】[Cqoi2006]凸多边形 半平面交
- BZOJ 2618 [Cqoi2006]凸多边形 半平面交
- 2618: [Cqoi2006]凸多边形
- 2618: [Cqoi2006]凸多边形
- 2618: [Cqoi2006]凸多边形
- bzoj 2618: [Cqoi2006]凸多边形 (半平面交)
- bzoj 2618: [Cqoi2006]凸多边形(半平面交模板)
- BZOJ 2618: [Cqoi2006]凸多边形(半平面交)
- 【CQOI2006】凸多边形
- [CQOI2006] 凸多边形
- 【CQOI2006】【BZOJ2618】凸多边形
- bsoj1156 【CQOI2006】 凸多边形
- bzoj2618【CQOI2006】凸多边形
- 【CQOI2006】凸多边形 计算几何
- BZOJ 1927 [Sdoi2010]星际竞速
- 源码-Integer的缓存
- this关键字——java
- 织梦DEDE系统建站 站长必备使用技巧 绝对的干货 掌柜呕心沥血总结
- Spring自我学习
- BZOJ 2618 [Cqoi2006]凸多边形
- java 四种内部类 使用细节(含代码)
- 实现append()难点
- iOS 小知识-单元测试中测试线程竞争
- 一些常用的第三方控件
- BZOJ 3436 小K的农场
- javascript/前端 有关数组的面试题
- Sass入门(二)
- 欢迎使用CSDN-markdown编辑器