1. 程式人生 > >Say Cheese UVA - 1001 (建圖+floyd)

Say Cheese UVA - 1001 (建圖+floyd)

傳送門

題意:無限大的乳酪裡有n個球形的洞,幫助小老鼠A用最短的時間到達小老鼠O的所在位置,乳酪裡的移動速度為10秒一個單位,但是在洞裡可以瞬間移動,洞和洞可以相交,輸入n個球的位置和半徑,以及A和O的座標,求最短時間。

題解:把起點A和終點O都看成是半徑為0的球,共有n+2個球,每個球的球心看成結點,若兩個球(p1,r1)和(p2,r2)所對應的結點之間的距離為d=|p1-p2|-r1-r2,如果d<0,說明兩個球相交,認為相應的距離為0。求出所有的距離之後,任意兩個球對應結點之間都有一個距離為d的無向邊,使用floyd演算法可以求出A和O的最短距離。

附上程式碼:


#include<bits/stdc++.h>

using namespace std;

const int maxn=1e2+50;
const double eps=1e-8;

double d[maxn][maxn];

struct Point{
    double x,y,z;
    Point(double _x=0,double y=0,double z=0):x(x),y(y),z(z){}
};

double length(Point a,Point b)
{
    double ans=(a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y)+(a.z-b.z)*(a.z-b.z);
    return sqrt(ans);
}

int dcmp(double ans)
{
    if(fabs(ans)<eps){
        return 0;
    }else{
        return ans<0?-1:1;
    }
}

struct Sphere{
    Point center;double radius;
};
Sphere S[maxn];

double Distance(Sphere a,Sphere b)
{
    double ans=length(a.center,b.center)-a.radius-b.radius;
    if(dcmp(ans)<0){
        ans=0;
    }
    return ans*10;
}

int main()
{
    int n,t=1;
    while(scanf("%d",&n)==1&&n>0){
        for(int i=0;i<n;i++){
            scanf("%lf%lf%lf%lf",&S[i].center.x,&S[i].center.y,&S[i].center.z,&S[i].radius);
        }
        scanf("%lf%lf%lf",&S[n].center.x,&S[n].center.y,&S[n].center.z);
        S[n].radius=0;
        n++;
        scanf("%lf%lf%lf",&S[n].center.x,&S[n].center.y,&S[n].center.z);
        S[n].radius=0;
        n++;
        for(int i=0;i<n;i++){
            d[i][i]=0;
            for(int j=i+1;j<n;j++){
                d[i][j]=d[j][i]=Distance(S[i],S[j]);
            }
        }
        for(int k=0;k<n;k++){
            for(int i=0;i<n;i++){
                for(int j=0;j<n;j++){
                    d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
                }
            }
        }
        printf("Cheese %d: Travel time = %.0lf sec\n",t++,d[n-1][n-2]);
    }
    return 0;
}