题意 : 有个人在湖中心的圆台上,需要跑到湖外,湖上游鳄鱼,需要踩着鳄鱼跳出去,每次能跳的距离是d,给定n条鳄鱼的坐标,问是否能跳到湖外。
思路很简单,令0表示湖心,n+1表示湖外,用spfa求0到n+1的最短路径,其中0到1~n的距离用1~n减7.5代替,n+1到1~n的距离,用距离湖外的最短距离代替。
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cstring>
#include <climits>
#include <cmath>
#include <queue>
using namespace std;
#define MEM(a,x) memset(a , x , sizeof(a))
int gcd(int a,int b){ return b==0?a:gcd(b,a%b); }
typedef long long llt ;
#define INF 1e15
typedef double weight_t;
const int SIZE_E = 9000;
const int SIZE_V = 1500;
struct point_t{
double x;
double y;
point_t(double xx=0.,double yy=0.){x=xx;y=yy;}
}Point[SIZE_V];
double disT( point_t const &a,point_t const&b){
return sqrt( (a.x-b.x)*(a.x-b.x) + (a.y-b.y)*(a.y-b.y) );
}
int ECnt = 0;
struct edge_t{
int v;
weight_t w;
edge_t *next;
}Edge[SIZE_E];
edge_t *V[SIZE_V];
void mkEdge(int const &a,int const &b,weight_t const &w){
Edge[ECnt].v = b;
Edge[ECnt].w = w;
Edge[ECnt].next = V[a];
V[a] = Edge+ECnt++;
Edge[ECnt].v = a;
Edge[ECnt].w = w;
Edge[ECnt].next = V[b];
V[b] = Edge+ECnt++;
}
weight_t D[SIZE_V];
bool flag[SIZE_V];
int pre[SIZE_V];//记录前驱
void spfa(int s,int n){
for(int i=0;i<=n+1;i++)
{
D[i]= INF;
flag[i]=0;
pre[i]=-1;
}
D[s] = 0;
flag[s] = true;
queue<int>q;
q.push(s);
while(!q.empty()){
int u = q.front();
q.pop();
flag[u] = false;
for(edge_t *p = V[u];p;p = p->next){
int v = p->v;
weight_t temp = D[u] + p->w;
if (temp < D[v]){
D[v] = temp;
pre[v] = u;
if (!flag[v]){
flag[v] = true;
q.push(v);
}
}
}
}
}
void init(){
ECnt = 0;
memset(V,0,sizeof(V));
MEM(Edge,0);
}
int main(){
Point[0].x = 0;
Point[0].y = 0;
int n;
double d;
while(scanf("%d%lf",&n,&d) != EOF){
init();
for (int i = 1;i <= n;++i)
scanf("%lf%lf",&Point[i].x,&Point[i].y);
double tmp;
//两个边求一个距离,如果小于D,则有通路
for (int i = 1;i <= n;++i)for (int j = i+1;j <= n;++j){
tmp = disT(Point[i],Point[j]);
if ( d >= tmp )
mkEdge(i,j,tmp );
}
//另Point[0]存圆台上的所有点,Point[n+1]存湖外的点
for (int i = 1;i <= n;++i){
//点到原点的距离-7.5
tmp = disT(Point[0],Point[i]) - 7.5;
if ( d >= tmp && tmp > 0)
mkEdge(0,i,tmp);
//距离湖外最近的距离与d比较
tmp = 50.0 - max( fabs(Point[i].x) , fabs(Point[i].y) ) ;
if ( d >= tmp && tmp > 0)
mkEdge(n+1,i,tmp);
}
spfa(0,n);
int idx = n+1,ans = 0;
//利用pre前驱数组计算通过的鳄鱼数
while(idx > 0)
idx = pre[idx],ans++;
if (D[n+1] >= INF)
printf("can't be saved\n");
else
printf("%.2lf %d\n",D[n+1],ans);
}
return 0;
}