码迷,mamicode.com
首页 > 其他好文 > 详细

计算几何

时间:2015-08-25 21:00:28      阅读:140      评论:0      收藏:0      [点我收藏+]

标签:

(一)半平面交:化出一些一元二次不等式,然后就可以求一些半平面交来找合法解了。

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");
}
View Code

 

(二)圆

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);
}
View Code

 

计算几何

标签:

原文地址:http://www.cnblogs.com/Rivendell/p/4758380.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!