zoj2318 getout(计算几何)

来源:互联网 发布:手机dj软件 编辑:程序博客网 时间:2024/06/16 15:32

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=1318

题意:

你是一个圆,二维坐标中有很多其他n个圆,给出n个圆心及半径,再给你自己的圆心及半径,问这个圆能不能逃出这n个圆的包围。

tip:

好神奇的题。。首先考虑把自己这个圆变成点,把别的圆的半径加上自己这个半径就好了。如果某两个圆相交或相切,那么他们组成的封闭区间可以用连接其两圆心的线段表示,这样能得到若干线段,于是问题变成,若干线段中,是否能组成一个封闭区域,且起始圆心在其内。
按顺时针扫描每一条边,如果点在里面,点与所有线段两个端点角度和为2π,如果逆时针来,就是-2π。 如果在多边形外的话,和必然是0,于是加边i j 边权为从起始圆心到I和到j的角度和(正负各加一条),如果整个图有负环,就相当于找到一个-2π,说明出不去了,spfa即可。。

#include <cstdio>#include <iostream>#include <cstring>#include <queue>#include <cmath>#include <algorithm>using namespace std;const int maxn = 340;const double eps = 1e-8;int n,tot,head[maxn],num[maxn];bool inq[maxn];struct Tcircle{    double x,y,r;}p[maxn];double dis[maxn];struct node{    int u,v,next;    double w;}edges[maxn*maxn];void add(int u,int v,double w){    edges[tot].v = v;edges[tot].w = w;edges[tot].next = head[u];head[u] = tot++;}void init(){    tot = 0;memset(head,-1,sizeof(head));    scanf("%d",&n);    for(int i = 1 ;i <= n ; i++){        scanf("%lf%lf%lf",&p[i].x,&p[i].y,&p[i].r);    }    scanf("%lf%lf%lf",&p[0].x,&p[0].y,&p[0].r);    for(int i = 1; i <= n ; i++)        p[i].r += p[0].r;}double dist(int i,int j){    return sqrt( (p[i].x-p[j].x)*(p[i].x-p[j].x)+(p[i].y-p[j].y)*(p[i].y-p[j].y) );}bool spfa(){    queue<int>q;    for(int i = 1;i <= n;i++){        q.push(i);        inq[i] = true;        num[i] = 0;        dis[i] = 0.0;    }    while(!q.empty()){        int tmp = q.front();q.pop();        inq[tmp] = 0;        for(int k = head[tmp];k != -1;k = edges[k].next){            if(dis[edges[k].v] > eps+dis[tmp]+edges[k].w){                dis[edges[k].v] = dis[tmp]+edges[k].w;                if(!inq[edges[k].v]){                    inq[edges[k].v] = true;                    q.push(edges[k].v);                    num[edges[k].v]++;                    if(num[edges[k].v] > n-1)       return true;                }            }        }    }    return false;}void sov(){    for(int i = 1; i <= n ; i++){        for(int j = i+1 ; j <= n ; j++){            if(p[i].r+p[j].r-dist(i,j) <= eps)   continue;            double ang = ( (p[i].x-p[0].x)*(p[j].x-p[0].x) + (p[i].y-p[0].y)*(p[j].y-p[0].y) )/dist(0,i)/dist(0,j);            ang = acos(ang);            if( (p[i].x-p[0].x) *(p[j].y-p[0].y) - (p[j].x-p[0].x) * (p[i].y-p[0].y) >= 0){                add(i,j,ang);add(j,i,-ang);            }            else{                add(i,j,-ang);add(j,i,ang);            }        }    }}int main(){    int T;    scanf("%d",&T);    while(T--){        init();        sov();        if(spfa())  printf("NO\n");        else    printf("YES\n");        if(T)   printf("\n");    }}
原创粉丝点击