HDU1245(Saving James Bond)最短路径Floyd

/*********************************************

题目大意:

有一个100*100的正方形湖,湖中间有一个直径为15的圆形小岛;

有n个点随机分布在这个正方形中;

一个人要从小岛上跳出湖外,可以跳跃在这些点上;

人每一步能跳的最大距离为d;

求能跳出湖外所需的最小的跳跃距离和步数;



算法分析:

首先计算每个坐标两两间的距离;

然后找出所有能从小岛上一步跳到的点存入数组s中;

然后找出所有能一步跳出湖外的点存入数组t中;

设置两个虚拟的顶点s和t;

用s与数组s中的所有顶点相连;

用t与数组t中的所有顶点相连;

即此题可以转换成求s到t的最短路径;



算法补充:

在建图的过程中,如果两个顶点之间的距离大于d了;

即两个顶点之间无法一步到达,所以此时将权值赋为无穷大;

此题很是有点卡精度,下面的代码GUN C++始终过不了,只能用C++过;

不知道是sqrt的问题还是double的问题,蛋碎了一地;

**********************************************/

#include<iostream>

#include<cstring>

#include<cmath>

#include<cstdio>

#include<cstdlib>

using namespace std;



const int N=110;

const double INF=10e8;

const double eps = 10e-8;



double G[N][N];//建图

int step[N][N];//计算走的步数

int s[N];//存放能从小岛上一步跳到的点

int t[N];//存放能一步跳出湖外的点

int n;//有效顶点数

double d;//一步能跳的距离



struct Point

{

    int x,y;

} p[N];



double min(double a,double b)

{

    return a<b?a:b;

}



double dist(int a,int b)

{

    return sqrt(double(a*a)+(double)b*b);

}



void floyd(int n)

{

    for(int k=0; k<=n; k++)

    {

        for(int i=0; i<=n; i++)

        {

            for(int j=0; j<=n; j++)

            {

                if(G[i][j]-G[i][k]-G[k][j]>eps)

                {

                    G[i][j]=G[i][k]+G[k][j];

                    step[i][j]=step[i][k]+step[k][j];

                }

            }

        }

    }

}



void solve()

{

    if(n==1)//没有符合题意的点

    {

        if(d-42.50>=eps)//直接一步可以从小岛跳出湖外

            puts("42.50 1");

        else

            puts("can't be saved");

        return;

    }



    for(int i=0; i<=n; i++)

        for(int j=0; j<=n; j++)

        {

            G[i][j]=INF;

            step[i][j]=0;

        }



    for(int i=1; i<n; i++)

    {

        for(int j=1; j<n; j++)

        {

            if(i==j)

            {

                G[i][j]=0;

                continue;

            }

            G[i][j]=G[j][i]=dist(p[i].x-p[j].x,p[i].y-p[j].y);

            step[i][j]=step[j][i]=1;

            if(G[i][j]-eps>d)//两根柱子无法一步跳过去

            {

                G[i][j]=G[j][i]=INF;

                step[i][j]=step[j][i]=0;

            }

        }

    }



    int len1=0;//能从小岛上一步跳到的点的个数

    int len2=0;//能一步跳出湖外的点的个数

    for(int i=1; i<n; i++)

    {

        if(dist(p[i].x,p[i].y)-7.50-d<=eps)//能从小岛上一步跳到的点

        {

            s[len1]=i;

            len1++;

        }

        if((p[i].x*1.0+d-50.00>=eps)||(p[i].x*1.0-d+50.00<=eps)||(p[i].y*1.0-d+50.00<=eps)||(p[i].y*1.0+d-50.00>=eps))//能一步跳出湖外的点

        {

            t[len2]=i;

            len2++;

        }

    }



    for(int i=0; i<len1; i++)//初始化虚拟顶点0

    {

        G[s[i]][0]=G[0][s[i]]=dist(p[s[i]].x,p[s[i]].y)-7.5;

        step[s[i]][0]=step[0][s[i]]=1;

    }

    for(int i=0; i<len2; i++)//初始化虚拟顶点n

    {

    	G[t[i]][n]=G[t[i]][n]=min(fabs(abs(p[t[i]].x)-50.00+eps),fabs(abs(p[t[i]].y)-50.00)+eps); //能一步跳出湖外的点的最小值

        step[n][t[i]]=step[t[i]][n]=1;

    }



    floyd(n);

    if(fabs(G[0][n]-INF)<eps)

        puts("can't be saved");

    else

        printf("%.2lf %d\n",G[0][n],step[0][n]);

}



int main()

{

    //freopen("C:\\Users\\Administrator\\Desktop\\kd.txt","r",stdin);

    while(~scanf("%d%lf",&n,&d))

    {

        int j=1;

        for(int i=1; i<=n; i++)

        {

            int x,y;

            scanf("%d%d",&x,&y);

            if(abs(x)*1.0-7.5<=eps&&abs(y)*1.0-7.5<=eps)//点在小岛内

                continue;

            if(abs(x)*1.0-50>=eps&&abs(y)*1.0-50>=eps)//点在小岛外

                continue;

            p[j].x=x;

            p[j].y=y;

            j++;

        }

        n=j;

        solve();

    }

    return 0;

}


你可能感兴趣的:(James)