/********************************************* 题目大意: 有一个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; }