天天看點

Gym - 100851F[最短路+枚舉]

題目連結: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;
}
           

繼續閱讀