题目链接:
http://acm.hust.edu.cn/vjudge/problem/307216
Froggy Ford
题意
青蛙过河,河中有若干个石头,现在你可以加一个石头,使得青蛙从左岸跳到右岸的最大跳跃距离最小。
题解
把左岸和右岸作为两个虚节点,用kruskal的思路处理出每个点到左岸需要跳跃的最大距离st[i](最优情况下)和每个点到右岸的最大距离ed[i],然后枚举两个点,在这两个点的中点放一个石头,得到ma=max(st[i],ed[j],dis(i,j)/2),如果这个值比答案更优,就更新答案,同时记录新放的石头的坐标。
代码
#include<map>
#include<cmath>
#include<queue>
#include<vector>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define X first
#define Y second
#define mkp make_pair
#define lson (o<<1)
#define rson ((o<<1)|1)
#define mid (l+(r-l)/2)
#define sz() size()
#define pb(v) push_back(v)
#define all(o) (o).begin(),(o).end()
#define clr(a,v) memset(a,v,sizeof(a))
#define bug(a) cout<<#a<<" = "<<a<<endl
#define rep(i,a,b) for(int i=a;i<(b);i++)
typedef long long LL;
typedef vector<int> VI;
typedef pair<int,int> PII;
typedef vector<pair<int,int> > VPII;
const int INF=0x3f3f3f3f;
const LL INFL=9e18;
const double eps=1e-8;
const int maxn=1111;
LL w,n;
pair<LL,LL> pt[maxn];
LL dis(LL x1,LL y1,LL x2,LL y2){
return (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2);
}
struct Edge{
int u,v;
LL w;
Edge(int u,int v,LL w):u(u),v(v),w(w){}
Edge(){}
bool operator < (const Edge& tmp) const {
return w<tmp.w;
}
}egs[maxn*maxn];
int tot;
int fa[maxn];
int find(int x){
return fa[x]=fa[x]==x?x:find(fa[x]);
}
vector<int> G[maxn];
int st[maxn],ed[maxn];
void init(){
clr(st,-1);
clr(ed,-1);
tot=0;
rep(i,0,maxn) fa[i]=i;
rep(i,0,maxn) G[i].push_back(i);
}
int main() {
freopen("froggy.in","r",stdin);
freopen("froggy.out","w",stdout);
init();
scanf("%I64d%I64d",&w,&n);
rep(i,1,n+1) scanf("%I64d%I64d",&pt[i].X,&pt[i].Y);
rep(i,1,n+1){
egs[tot++]=Edge(0,i,pt[i].X*pt[i].X);
}
rep(i,1,n+1){
egs[tot++]=Edge(i,n+1,(w-pt[i].X)*(w-pt[i].X));
}
rep(i,1,n+1){
rep(j,i+1,n+1){
egs[tot++]=Edge(i,j,dis(pt[i].X,pt[i].Y,pt[j].X,pt[j].Y));
}
}
egs[tot++]=Edge(0,n+1,w*w);
egs[tot++]=Edge(0,0,0);
egs[tot++]=Edge(n+1,n+1,0);
sort(egs,egs+tot);
rep(i,0,tot){
int u=egs[i].u,v=egs[i].v;
if(u==0&&v==0){
st[0]=i; continue;
}
if(u==n+1&&v==n+1){
ed[n+1]=i; continue;
}
int pu=find(u);
int pv=find(v);
if(pu!=pv){
if(find(0)==pu){
rep(j,0,G[pv].size()){
int tt=G[pv][j];
st[tt]=i;
}
}else if(find(0)==pv){
rep(j,0,G[pu].size()){
int tt=G[pu][j];
st[tt]=i;
}
}
if(find(n+1)==pu){
rep(j,0,G[pv].size()){
int tt=G[pv][j];
ed[tt]=i;
}
}else if(find(n+1)==pv){
rep(j,0,G[pu].size()){
int tt=G[pu][j];
ed[tt]=i;
}
}
fa[pv]=pu;
while(G[pv].size()>0){
G[pu].push_back(G[pv][G[pv].sz()-1]);
G[pv].pop_back();
}
}
}
int ans_i=0,ans_j=0;
double mi=9000000000000000000;
rep(i,0,n+2){
rep(j,0,n+2){
if(i==j) continue;
double tmp=max(egs[st[i]].w,egs[ed[j]].w);
int ti=i,tj=j;
if(ti>tj) swap(ti,tj);
if(ti==0&&tj==n+1){
tmp=max(tmp,w*w*1.0/4);
}else if(ti==0){
tmp=max(tmp,pt[tj].X*pt[tj].X*1.0/4);
}else if(tj==n+1){
tmp=max(tmp,(w-pt[ti].X)*(w-pt[ti].X)*1.0/4);
}else{
tmp=max(tmp,dis(pt[i].X,pt[i].Y,pt[j].X,pt[j].Y)*1.0/4);
}
if(tmp<mi){
mi=tmp;
ans_i=i; ans_j=j;
}
}
}
double ans_x=0,ans_y=0;
if(ans_i>ans_j) swap(ans_i,ans_j);
if(ans_i==0&&ans_j==n+1){
ans_x=w*1.0/2;
ans_y=0;
}else if(ans_i==0){
ans_x=pt[ans_j].X*1.0/2;
ans_y=pt[ans_j].Y;
}else if(ans_j==n+1){
ans_x=(w+pt[ans_i].X)*1.0/2;
ans_y=pt[ans_i].Y;
}else{
ans_x=(pt[ans_i].X+pt[ans_j].X)*1.0/2;
ans_y=(pt[ans_i].Y+pt[ans_j].Y)*1.0/2;
}
printf("%.3lf %.3lf
",ans_x,ans_y);
return 0;
}