标签:
(一)半平面交:化出一些一元二次不等式,然后就可以求一些半平面交来找合法解了。
bzoj1007 水平可见直线
题目大意:给定一些直线,求从无限高处可以看到那些直线。
思路:对于每一条直线都是一个半平面,然后加上无穷远的半平面之后求半平面交,用到的就是。这里无穷远的半平面可以赋成1e100防止错误。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxnode 50005 #define inf 1e100 #define eps 1e-20 using namespace std; struct point{double x,y;}p[maxnode]={0}; struct vector{double x,y;}; int n,que[maxnode]={0}; bool use[maxnode]={false}; double dis(double x,double y){return sqrt(x*x+y*y);} point operator + (point a,vector b){return (point){a.x+b.x,a.y+b.y};} vector operator - (point a,point b){return (vector){a.x-b.x,a.y-b.y};} vector operator * (vector a,double b){return (vector){a.x*b,a.y*b};} struct line{ point p;vector v; double ang;int po; void init(double k,double b) { p=(point){0.0,b*1.0}; double dd=dis(1.0,k*1.0); v.x=1.0/dd;v.y=k*1.0/dd; ang=atan2(v.y,v.x); } bool operator < (const line &a) const{return ang<a.ang;} }ai[maxnode]; double cross(vector a,vector b){return a.x*b.y*1.0-a.y*b.x*1.0;} bool onleft(line a,point b){return cross(a.v,b-a.p)>0;} point getjiao(line a,line b) { vector u=a.p-b.p; double t=cross(b.v,u)/cross(a.v,b.v); return a.p+a.v*t; } void get() { int head,tail,i; ai[++n].p=(point){inf,0};ai[n].v=(vector){0,1}; ai[n].po=0;ai[n].ang=atan2(1,0); ai[++n].p=(point){0,inf};ai[n].v=(vector){-1,0}; ai[n].po=0;ai[n].ang=atan2(0,-1); ai[++n].p=(point){-inf,0};ai[n].v=(vector){0,-1}; ai[n].po=0;ai[n].ang=atan2(-1,0); ai[++n].p=(point){0,-inf};ai[n].v=(vector){1,0}; ai[n].po=0;ai[n].ang=atan2(0,1); sort(ai+1,ai+n+1);que[head=tail=1]=1; for (i=2;i<=n;++i) { while(head<tail&& !onleft(ai[i],p[tail-1])) --tail; while(head<tail&& !onleft(ai[i],p[head])) ++head; que[++tail]=i; if (fabs(cross(ai[que[tail]].v,ai[que[tail-1]].v))<eps) { --tail; if (onleft(ai[que[tail]],ai[i].p)) que[tail]=i; } if (head<tail) p[tail-1]=getjiao(ai[que[tail-1]],ai[que[tail]]); } while(head<tail&&!onleft(ai[que[head]],p[tail-1])) --tail; for (i=head;i<=tail;++i) use[ai[que[i]].po]=true; } int main() { int i,j;double k,b; scanf("%d",&n); for (i=1;i<=n;++i) { scanf("%lf%lf",&k,&b); ai[i].init(k,b);ai[i].po=i; } get(); for (i=1;i<=n;++i) if (use[i]) printf("%d ",i); printf("\n"); }
(二)圆
bzoj1043 下落的圆盘
题目大意:一堆圆盘,后面的会挡住前面的,求最后露出来的圆周的长度和。
思路:对于每个圆盘,看他后面有没有能包含他的,那这个圆盘对答案没有贡献;如果没有,就看一下后面和他相交的,把相应的区段左右极角存下来,转化到0~2pi的区间,排序后扫一遍,求一下露出来的部分就可以了。注意转到0~2pi时,如果<0就+2pi,如果右端点小于左端点了,就可以拆成两个区间;在求答案的时候,不要忘了加上最后一段的区间(x~2pi)的位置。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define maxnode 1005 using namespace std; struct xl{ double x,y; }; struct use{ double r,x,y; }cir[maxnode]={0}; struct uu{ double l,r; }zh[maxnode]={0}; int n; double pi; int cmp(const uu &a,const uu &b){return a.l==b.l ? a.r<b.r : a.l<b.l;} double ab(double a){return a>=0 ? a : -a;} double jijiao(xl a){return atan2(a.y,a.x);} xl jia(xl a,xl b){return (xl){a.x+b.x,a.y+b.y};} xl jian(use a,use b){return (xl){a.x-b.x,a.y-b.y};} xl cheng(xl a,double b){return (xl){a.x*b,a.y*b};} xl chu(xl a,double b){b*=1.0;return (xl){a.x/b,a.y/b};} double chaji(xl a,xl b){return a.x*b.x+a.y*b.y;} double lenth(xl a){return sqrt(chaji(a,a));} double cross(xl a,xl b){return a.x*b.y-a.y*b.x;} xl dwxl(xl a){return chu(a,lenth(a));} bool cover(use a,use b) {return (a.r>=b.r+lenth(jian(a,b)));} bool jiao(use a,use b) { double len=lenth(jian(a,b)); return (len<a.r+b.r&&len>(ab(a.r-b.r))); } double work(int a) { int i,j,tot=0;double len,ll,dd; for (i=a+1;i<=n;++i) if (cover(cir[i],cir[a])) return 0; for (i=a+1;i<=n;++i) { if (jiao(cir[a],cir[i])) { len=lenth(jian(cir[a],cir[i])); ll=atan2(cir[i].y-cir[a].y,cir[i].x-cir[a].x); dd=(cir[a].r*cir[a].r+len*len-cir[i].r*cir[i].r)*1.0/(2.0*len*cir[a].r); zh[++tot].l=ll-acos(dd); zh[tot].r=ll+acos(dd); if (zh[tot].l<0) zh[tot].l+=2*pi; if (zh[tot].r<0) zh[tot].r+=2*pi; if (zh[tot].l>zh[tot].r) { zh[++tot].l=0;zh[tot].r=zh[tot-1].r;zh[tot-1].r=2*pi; } } } sort(zh+1,zh+tot+1,cmp); len=ll=dd=0; for (i=1;i<=tot;++i) { if (zh[i].l<=dd) dd=max(dd,zh[i].r); else {len+=zh[i].l-dd;dd=zh[i].r;} } len+=2*pi-dd; return len*cir[a].r; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int i,j;double ans=0; scanf("%d",&n);pi=acos(-1); for (i=1;i<=n;++i) scanf("%lf%lf%lf",&cir[i].r,&cir[i].x,&cir[i].y); for (i=1;i<=n;++i) ans+=work(i); printf("%.3f\n",ans); fclose(stdin); fclose(stdout); }
标签:
原文地址:http://www.cnblogs.com/Rivendell/p/4758380.html