SWUST OJ 1025

地址:http://acm.swust.edu.cn/oj/problem/1025/


Description

TT lives in a dream world.All countries in the world are circular or rectangular.There is a moat on the territorial border of each country.(the edge of the circle or the rectangle).The water in the moat flow in one direction,so people in the country can travel in the moat by ship.

Now there are N countries numbered 1,2,3……N.TT is in the moat of the country numbered 1.He wants to get to the country numbered N.(get to the country's moat)How much distance does TT have to walk(not by ship) at least?

Input

The input consists of multiple test cases.

For each case,the first line contains one integer N(2<=N<=200),the number of countries in this world,then N lines follow,the ith line indicates the information of the country numbered i.Here is the detail:

C X Y R:indicate the country numbered i is a circle,and the center of the circle is(X,Y),the radius is R.(0<=R<=10^6)

R X1 Y1 X2 Y2(X1!=X2,Y1!=Y2):indicate the country numbered i is a rectangle,and the two vertexs of one diagonal are (X1,Y1) and (X2,Y2). (-10^6<X,Y,X1,Y1,X2,Y2<10^6).

We guarantee that any two countries don't overlap.

The input terminates with the integer 0. 

Output

The minimum distance TT has to walk.Please keep two decimal places.

Sample Input

2
C 0 0 1
R 1 5 2 6
3
C 0 0 1
C 2 2 1
R 3 0 4 1
0

Sample Output

4.10
1.24
Hint
由于OJ上传数据的BUG,换行请使用"\r\n",非常抱歉
Source

求点1到点n的最短距离,保留2位小数,这部分很裸的最短路

关键是把边的距离求出来,它的点是圆或者矩形(无重叠),要求出两个图形的最短距离.

圆和圆的距离就是圆心距减去半径和

圆到矩形的距离,可以把矩形看成4条线段,也就是圆心到线段的距离

矩形到矩形的距离,分别看成4条线段....


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <queue>
#include <vector>
using namespace std;

#define eps 1e-6
#define PI acos(-1.0)

struct Point{
    double x,y;
    Point(double _x,double _y):x(_x),y(_y){}
};
struct Seg{
    Point a,b;
    Seg(Point _a,Point _b):a(_a),b(_b){}
};
struct Circle{
    Point cen;
    double r;
    int id;
    Circle(Point _cen,double _r,int _id):cen(_cen),r(_r),id(_id){}
};
struct Rec{
    Point a,b;
    int id;
    Rec(Point _a,Point _b,int _id):a(_a),b(_b),id(_id){}
};

//点之间的距离
inline double len(Point a,Point b){
    return sqrt((a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y));
}

//余弦定理算夹角
inline double angle(Point a,Point b,Point c){
    double l1=len(a,b);
    double l2=len(a,c);
    double l3=len(b,c);
    return acos((l1*l1+l2*l2-l3*l3)/(2*l1*l2));
}

//点到线段的距离
inline double dis(Point a,Seg b){
    double ang=angle(b.a,a,b.b);
    if(ang<(PI/2) || fabs(ang-PI/2)<eps){
        double l1=len(a,b.a);
        double l2=len(b.a,b.b);
        double ll=l1*cos(ang);
        if(ll<l2 || fabs(ll-l2)<eps) return l1*sin(ang);
        else return min(len(a,b.a),len(a,b.b));
    }
    else{
        ang=angle(b.b,a,b.a);
        double l1=len(a,b.b);
        double l2=len(b.a,b.b);
        double ll=l1*cos(ang);
        if(ll<l2 || fabs(ll-l2)<eps) return l1*sin(ang);
        else return min(len(a,b.a),len(a,b.b));
    }
}

//线段到线段的距离(线段不相交)
inline double solve(Seg a,Seg b){
    return min(min(dis(a.a,b),dis(a.b,b)),min(dis(b.a,a),dis(b.b,a)));
}

//圆到线段的距离
inline double solve(Circle a,Seg b){
    return dis(a.cen,b)-a.r;
}

//圆到圆的距离
inline double solve(Circle a,Circle b){
    return len(a.cen,b.cen)-(a.r+b.r);
}

//圆到矩形的距离,把矩形看成4条线段,求最小值
inline double solve(Circle a,Rec b){
    Point x(b.a.x,b.b.y);
    Point y(b.b.x,b.a.y);

    double l1=solve(a,Seg(b.a,x));
    double l2=solve(a,Seg(x,b.b));
    double l3=solve(a,Seg(b.b,y));
    double l4=solve(a,Seg(y,b.a));
    return min(min(l1,l2),min(l3,l4));
}

//线段到矩形的距离,把矩形看成4条线段,求最小值
inline double solve(Seg a,Rec b){
    Point x(b.a.x,b.b.y);
    Point y(b.b.x,b.a.y);

    double l1=solve(a,Seg(b.a,x));
    double l2=solve(a,Seg(x,b.b));
    double l3=solve(a,Seg(b.b,y));
    double l4=solve(a,Seg(y,b.a));
    return min(min(l1,l2),min(l3,l4));
}

//矩形到矩形的距离,把其中一个矩形看成4条线段,求最小值
inline double solve(Rec a,Rec b){
    Point q(a.a.x,a.b.y);
    Point w(a.b.x,a.a.y);

    double l1=solve(Seg(a.a,q),b);
    double l2=solve(Seg(q,a.b),b);
    double l3=solve(Seg(a.b,w),b);
    double l4=solve(Seg(w,a.a),b);
    return min(min(l1,l2),min(l3,l4));
}


int n;
char s[2];
double x,y,c,d;
vector<Circle>cir;
vector<Rec>rec;
double map[205][205],ans[205];
bool vis[205];

inline double spfa(){
    queue<int>q;
    q.push(1);
    for(int i=1;i<=n;i++) ans[i]=1000000000.0;
    ans[1]=0.0;
    memset(vis,0,sizeof(vis)),vis[1]=1;
    while(!q.empty()){
        int x=q.front();
        q.pop(),vis[x]=0;
        for(int i=1;i<=n;i++){
            if(i!=x && map[x][i]!=1000000000.0){
                double l=ans[x]+map[x][i];
                if(l<ans[i]){
                    ans[i]=l;
                    if(!vis[i]){
                        vis[i]=1;q.push(i);
                    }
                }
            }
        }
    }
    return ans[n];
}

int main(){
    while(scanf("%d",&n)&&n){
        cir.clear(),rec.clear();
        for(int i=1;i<=n;i++){
            scanf("%s",s);
            if(s[0]=='C'){
                scanf("%lf%lf%lf",&x,&y,&c);
                cir.push_back(Circle(Point(x,y),c,i));
            }
            else{
                scanf("%lf%lf%lf%lf",&x,&y,&c,&d);
                if(x>c) swap(x,c),swap(y,d);
                rec.push_back(Rec(Point(x,y),Point(c,d),i));
            }
        }

        for(int i=1;i<=n;i++){
            for(int j=1;j<=n;j++){
                map[i][j]=1000000000.0;
            }
            map[i][i]=0.0;
        }
        
        //求出任意两个物体之间的最短距离
        for(int i=0;i<cir.size();i++){
            int now=cir[i].id;
            for(int j=i+1;j<cir.size();j++){
                int a=cir[j].id;
                double l=solve(cir[i],cir[j]);
                if(map[now][a]>l){
                    map[now][a]=map[a][now]=l;
                }
            }
            for(int j=0;j<rec.size();j++){
                int a=rec[j].id;
                double l=solve(cir[i],rec[j]);
                if(map[now][a]>l){
                    map[now][a]=map[a][now]=l;
                }
            }
        }
        for(int i=0;i<rec.size();i++){
            int now=rec[i].id;
            for(int j=i+1;j<rec.size();j++){
                int a=rec[j].id;
                double l=solve(rec[i],rec[j]);
                if(map[now][a]>l){
                    map[now][a]=map[a][now]=l;
                }
            }
        }
        printf("%.2lf\r\n",spfa());
    }
    return 0;
}







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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值