Hdu 4063-Aircraft(计算几何+最短路)

题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4063

题目大意:
有n个圆,给出圆心和半径,第一个和最后一个圆的圆心分别为起点和终点,求起点是否可达终点,且路径上所有点必须在给出的圆内或圆上

分析:
画图可以发现,从起点出发的最短路径,必定经过圆心,或者两圆的交点,所以找出所有的两圆并去重,然后任意两点之间检查是否可达。

可达性的检查为,作出两点间的线段,同时检查该线段所在直线与所有圆的交点,保存在线段上的交点,最后对所有交点排序,若相邻两交点间的线段被某个圆包括则合法,否则非法,该两点不可达,不可建边。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-wZyRpKCI-1622049927811)(http://hi.csdn.net/attachment/201110/7/6627258_1317988620BYI7.jpg)]
两点之间的边的权值即是两点距离,然后对于建出的图直接跑dij或spfa即可,由于一开始排序去重了,点的顺序被打乱,所以需要一次遍历找回起点和终点,即与第一个和最后一个圆的圆心相同的点。

代码:
注:直接套了kuangbin的计算几何板子,很长

#include <cstdio>
#include <cmath>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

const double eps = 1e-8;
const double inf = 1e20;
const double pi = acos(-1.0);
const int maxp = 1010;

int sgn(double x){
    if (fabs(x)<eps) return 0;
    if (x<0) return -1;
    else return 1;
}

inline double sqr(double x)
{
    return x*x;
}

struct Point{
    double x,y;
    Point(){}
    Point(double _x,double _y){
        x = _x;
        y = _y;
    }
    void input(){
        scanf("%lf%lf",&x,&y);
    }
    void output(){
        printf("%2.f,%.2f\n",x,y);
    }
    bool operator == (Point b)const{
        return sgn(x-b.x)==0&& sgn(y-b.y)==0;
    }
    bool operator < (Point b)const{
        return sgn(x-b.x)==0?sgn(y-b.y)<0:x<b.x;
    }
    Point operator - (const Point & b)const{
        return Point(x-b.x,y-b.y);
    }
    //叉积
    double operator ^ (const Point &b)const{
        return x*b.y-y*b.x;
    }
    //点积
    double operator * (const Point &b)const{
        return x*b.x + y*b.y;
    }
    double len()
    {
        return hypot(x,y);
    }
    double len2()
    {
        return x*x+y*y;
    }

    double distance(Point p)
    {
        return hypot(x-p.x,y-p.y);
    }

    Point operator + (const Point & b) const
    {
        return Point(x+b.x,y+b.y);
    }

    Point operator *(const double& k)const{
        return Point(x*k,y*k);
    }

    Point operator / (const double &k) const{
        return Point(x/k,y/k);
    }
    double rad(Point a,Point b)
    {
        Point p = *this;
        return fabs(atan2 (fabs((a-p)^(b-p)),(a-p)*(b-p)));
    }

    Point trunc(double r)
    {
        double l = len();
        if (!sgn(l)) return *this;
        r /=l ;
        return Point (x*r,y*r);
    }

    Point rotleft(){
        return Point(-y,x);
    }

    Point rotright(){
        return Point(y,-x);
    }

    Point rotate(Point p,double angle)
    {
        Point v = (*this) - p;
        double c = cos(angle) , s = sin(angle);
        return Point(p.x+v.x*c - v.y*s,p.y+v.x*s + v.y*c);
    }

};

struct Line{
    Point s,e;
    Line(){}
    Line(Point _s,Point _e)
    {
        s = _s;
        e = _e;
    }
    bool operator == (Line v)
    {
        return (s==v.s)&&(e==v.e);
    }
    Line (Point p,double angle)
    {
        s = p;
        if (sgn(angle - pi/2) == 0)
        {
            e = (s + Point(0,1));
        }
        else
            e = (s +Point(1,tan(angle)));
    }

    Line (double a,double b,double c)
    {
        if (sgn(a)==0)
        {
            s = Point(0,-c/b);
            e = Point(1,-c/b);
        }
        else if (sgn(b)==0)
        {
            s = Point(-c/a,0);
            e = Point(-c/a,1);
        }
        else
        {
            s = Point(0,-c/b);
            s = Point(1,(-c-a)/b);
        }
    }
    void input()
    {
        s.input();
        e.input();
    }

    void adjust()
    {
        if (e<s) swap(s,e);
    }

    double length()
    {
        return s.distance(e);
    }

    double angle(){
        double k = atan2(e.y-s.y,e.x-s.x);
        if (sgn(k)<0) k+= pi;
        if (sgn(k-pi)==0) k -= pi;
        return k;
    }

    int relation(Point p)
    {
        int c = sgn((p-s)^(e-s));
        if (c<0) return 1;
        else if (c>0) return 2;
        else return 3;
    }

    bool pointonseg(Point p)
    {
        return sgn((p-s)^(e-s)) ==0 &&sgn((p-s)*(p-e))<=0;
    }

    bool parallel(Line v)
    {
        return sgn((e-s)^(v.e-v.s)) ==0;
    }

    int segcrossseg(Line v)
    {
        int d1 = sgn((e-s)^(v.s-s));
        int d2 = sgn((e-s)^(v.e-s));
        int d3 = sgn((v.e-v.s)^(s-v.s));
        int d4 = sgn((v.e-v.s)^(e-v.s));
        if ((d1^d2) ==-2 && (d3^d4)==-2 ) return 2;
        return (d1==0&& sgn((v.s-s)*(v.s-e))<=0)||
        (d2 ==0 && sgn((v.e-s)*(v.e-e))<=0)||
        (d3 ==0 && sgn((s-v.s)*(s-v.e))<=0)||
        (d4 ==0 && sgn((e-v.s)*(e-v.e))<=0);
    }

    Point crosspoint(Line v)
    {
        double a1 = (v.e-v.s)^(s-v.s);
        double a2 = (v.e-v.s)^(e-v.s);
        return Point((s.x*a2-e.x*a1)/(a2-a1),(s.y*a2-e.y*a1)/(a2-a1));
    }

    double dispointtoline(Point p)
    {
        return fabs((p-s)^(e-s))/length();
    }

    double dispointtoseg(Point p)
    {
        if (sgn((p-s)*(e-s))<0|| sgn((p-e)*(s-e))<0)
            return min(p.distance(s),p.distance(e));
        return dispointtoline(p);
    }

    Point lineprog(Point p)
    {
        return s + ( ((e-s)*((e-s)*(p-s)))/((e-s).len2()));
    }

};


struct circle{
    Point p;
    double r;
    circle() {}
    circle(Point _p , double _r)
    {
        p = _p;
        r = _r;
    }

    circle(Point a, Point b, Point c)
    {
        Line u = Line((a+b)/2,((a+b)/2)+((b-a).rotleft()));
        Line v = Line((b+c)/2,((b+c)/2)+((c-b).rotleft()));
        p = u.crosspoint(v);
        r = p.distance(a);
    }


    void input()
    {
        p.input();
        scanf("%lf",&r);
    }

    void output()
    {
        printf("%.2f,%.2f,%.2f\n",p.x,p.y,r);
    }

    bool operator == (circle v)
    {
        return (p==v.p)&&sgn(r-v.r)==0;
    }
    bool operator < (circle v)const
    {
        return ((p<v.p)||((p==v.p)&&sgn(r-v.r)<0));
    }

    double area()
    {
        return pi*r*r;
    }

    double circumference()
    {
        return 2*pi*r;
    }

    int relation(Point b)
    {
        double dst = b.distance(p);
        if (sgn(dst-r)<0) return 2;
        else if (sgn(dst-r)==0) return 1;
        return 0;
    }

    int relationseg(Line v)
    {
        double dst = v.dispointtoseg(p);
        if (sgn(dst-r) < 0) return 2;
        else if (sgn(dst -r) ==0) return 1;
        return 0;
    }

    int relationline (Line v)
    {
        double dst = v.dispointtoline(p);
        if (sgn(dst-r)<0) return 2;
        else if (sgn(dst-r)==0) return 1;
        return 0;
    }

    int relationcircle(circle v)
    {
        double d = p.distance(v.p);
        if (sgn(d-r-v.r)>0) return 5;
        if (sgn(d-r-v.r)==0) return 4;
        double l = fabs(r-v.r);
        if (sgn(d-r-v.r)<0 && sgn(d-l)>0) return 3;
        if (sgn(d-l) ==0 ) return 2;
        if (sgn(d-l)< 0) return 1;
    }

    int pointcrosscircle(circle v,Point& p1,Point& p2)
    {
        int rel = relationcircle(v);
        if (rel==1 || rel==5) return 0;
        double d = p.distance(v.p);
        double l = (d*d+r*r-v.r*v.r)/(2*d);
        double h = sqrt(r*r-l*l);
        Point tmp = p+ (v.p-p).trunc(l);
        p1 = tmp + ((v.p-p).rotleft().trunc(h));
        p2 = tmp + ((v.p-p).rotright().trunc(h));
        if (rel==2 || rel ==4)
            return 1;
        return 2;
    }

    int pointcorssline(Line v, Point &p1 , Point &p2)
    {
        if (!(*this).relationline(v))   return 0;
        Point a = v.lineprog(p);
        double d = v.dispointtoline(p);
        d = sqrt(r*r-d*d);
        if (sgn(d)==0)
        {
            p1 = a;
            p2 = a;
            return 1;
        }
        p1 = a + (v.e-v.s).trunc(d);
        p2 = a - (v.e-v.s).trunc(d);
        return 2;

    }


}c[50];

const int MAXN = 1000;
const int MAXM = 500000;

Point arr[5000];
int n,pc;
struct Edge{
    int from, to, next;
    double val;
    int id;
}edge[MAXM];

struct Node{
    int x;
    double  d;
    Node(){}
    Node( int a, double b ): x( a ), d( b ){}
    bool operator < ( Node a ) const{
        return d > a.d;
    }
};

int head[MAXN],cnt;
double dis[MAXN];

void init(){
    cnt = 0;
    for (int i = 0 ; i < MAXN ; i ++)
        dis[i] = inf;
    memset( head, -1, sizeof( head ) );
}

void add( int from, int to, double val ){
    edge[cnt].from = from;
    edge[cnt].to = to;
    edge[cnt].val = val;
    edge[cnt].next = head[from];
    head[from] = cnt++;
}

void dij( int s ){
    dis[s] = 0;

    priority_queue<Node> Q;
    Q.push( Node( s, dis[s] ) );

    while( !Q.empty() ){
        Node temp = Q.top(); Q.pop();
        int x = temp.x;
        if( temp.d > dis[x] ) continue;
        for( int k = head[x]; ~k; k = edge[k].next ){
            int y = edge[k].to;
            if( dis[y] > dis[x] + edge[k].val ){
                dis[y] = dis[x] + edge[k].val;
                Q.push( Node( y, dis[y] ) );
            }
        }
    }
}



bool check(Point a,Point b)
{
    if (b<a)
        swap(a,b);
    Point cs[500],p,q;
    int pt = 0;
    Line u = Line(a,b);
    for (int i = 1 ; i <= n ; i ++)
    {

        int res = c[i].pointcorssline(u,p,q);
        if (res==1&&u.pointonseg(p))
            cs[++pt] = p;
        else if (res==2)
        {
            if (u.pointonseg(p))
                cs[++pt] = p;
            if (u.pointonseg(q))
                cs[++pt] = q;
        }
    }
    sort(cs+1,cs+pt+1);
    pt = unique(cs+1,cs+pt+1) -cs - 1;
    for (int i = 2 ; i <= pt ; i ++)
    {
//        if ((cs[i]<a)||(b<cs[i]))
//            continue;
        int flag = 0;
        Point mid = Point((cs[i-1].x+cs[i].x)/2,(cs[i-1].y+cs[i].y)/2);
        for (int j = 1 ; j <= n ; j ++)
        {
            if (sgn(mid.distance(c[j].p)-c[j].r)<=0)
            {
//                cs[i-1].output();
//                cs[i].output();
//                c[j].output();
                flag = 1;
                break;
            }
        }
        if (!flag)
            return false;
    }
    return true;
}




int main()
{
    int T,t=1;
    Point p,q;
    scanf("%d",&T);
    while (T--)
    {
        init();
        scanf("%d",&n);
        for (int i = 1;  i <= n ; i ++)
        {
            c[i].input();
            arr[i] = c[i].p;
        }
        pc = n;
        for (int i = 1 ; i <= n ; i ++)
        {
            for (int j = i + 1 ; j <= n ; j ++)
            {
                int res = c[i].pointcrosscircle(c[j],p,q);
                if (res==1)
                    arr[++pc] = p;
                else if (res==2)
                {
                    arr[++pc] = p;
                    arr[++pc] = q;
                }
            }
        }
        sort(arr+1,arr+pc+1);
       // printf("pre pc = %d\n",pc);
        pc = unique(arr+1,arr+pc+1)- arr - 1;
       // printf("after pc = %d\n",pc);
        int st,ed;
        for (int i = 1 ; i <= pc ; i ++)
        {
            if (arr[i]==c[1].p) st = i;
            if (arr[i]==c[n].p) ed = i;
        }
       // printf("st= %d\ted= %d\n",st,ed);
        for (int i = 1 ; i <= pc ; i ++)
        {
            for (int j = i + 1; j <= pc ; j ++)
            {
                if (check(arr[i],arr[j]))
                {
                    //printf("-------------\n");
                    //arr[i].output();
                    //arr[j].output();
                    //printf("dis = %f\n",arr[i].distance(arr[j]));
                    //printf("-------------\n");

                    add(i,j,arr[i].distance(arr[j]));
                    add(j,i,arr[i].distance(arr[j]));

                }
            }
        }
        printf("Case %d: ",t++);
        dij(st);
        if (sgn(dis[ed]-inf)==0)
            printf("No such path.\n");
        else
            printf("%.4f\n",dis[ed]);




    }
    return 0;

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值