题目链接:https://vjudge.net/problem/Gym-100851F
解题思路:
一个明显的结论就是石头肯定是放在两个石头或者河岸之间的,所以正向跑一遍最短路,反向跑一遍最短路,然后枚举i和j中间放石头就好了。
由于相当于每个点都满边,所以只能去跑n^2最短路,不能用spfa了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
const int mx = 1e3+10;
int n,m,K;
int S,T;
bool vis[mx];
double dis1[mx],dis2[mx];
struct node{
double x,y;
}s[mx];
double dist(node A,node B)
{
if(A.x==m||A.x==0) return fabs(A.x-B.x);
if(B.x==m||B.x==0) return fabs(A.x-B.x);
return sqrt((A.x-B.x)*(A.x-B.x)+(A.y-B.y)*(A.y-B.y));
}
void spfa(int beg,double *dis)
{
for(int i=0;i<=T;i++)
dis[i] = 1e30,vis[i] = 0;
dis[beg] = 0;
int pos = 0,now = beg;
for(int i=0;i<=T;i++){
double d = 1e30;
for(int j=0;j<=T;j++)
if(!vis[j]&&dis[j]<d)
d = dis[pos=j];
vis[pos] = 1;
for(int j=0;j<=T;j++){
if(!vis[j]){
double v = max(dis[pos],dist(s[pos],s[j]));
dis[j] = min(dis[j],v);
}
}
}
}
int main(){
freopen("froggy.in","r",stdin);
freopen("froggy.out","w",stdout);
while(~scanf("%d%d",&m,&n)){
S = 0,T = n + 1;
s[0].x = 0,s[T].x = m;
for(int i=1;i<=n;i++)
scanf("%lf%lf",&s[i].x,&s[i].y);
spfa(S,dis1);
spfa(T,dis2);
double bx = 1,by = 1,mi = 1e30;
for(int i=0;i<T;i++){
for(int j=1;j<=T;j++){
double d = dist(s[i],s[j])/2;
d = max(d,max(dis1[i],dis2[j]));
if(mi>d){
mi = d;
if(i==0&&j==T){
bx = 1.0*m/2;
}else if(i==0){
bx = s[j].x/2;
by = s[j].y;
}else if(j==T){
bx = (s[i].x+m)/2;
by = s[i].y;
}else{
bx = (s[i].x+s[j].x)/2;
by = (s[i].y+s[j].y)/2;
}
}
}
}
printf("%.6lf %.6lf\n",bx,by);
}
return 0;
}