地址:http://acm.swust.edu.cn/oj/problem/1025/
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
求点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;
}