gym100851F Froggy Ford

http://codeforces.com/gym/100851

第一眼,这不是noip2015DAY2T1原题吗。。。。

然后发现不太行,不过变化一下就行了

先二分一个最大跳的距离mid,去判断能不能在一个额外的石子的条件下,使得每一跳都小于mid,由于从河岸到每个石子是垂直跳的,我们还要在河岸处每边增加n个点,来表示从河岸直接跳到对应点的距离,设置一个左边的超级源点,右边的超级汇点,分别开始dfs,标记哪些点左边能再不超过mid的情况下直接跳到,右边也是一样。然后枚举u,v两个点,如果左边能到u点,右边能到v点,且dist(u,v)<=2*mid,那么mid就是可行的,把石子加在u,v中间就行了。

#include<bits/stdc++.h>
#define maxl 3010
using namespace std;
 
const double eps=1e-5;
 
int w,n,S,T,cnt;
int ehead[maxl];
struct node
{
  int x,y;
}a[maxl];
struct ed
{
  int to,nxt;
  double l;
}e[2000*2000*2];
double ansx,ansy;
bool visS[maxl],visT[maxl];
 
inline double dist(double x,double y)
{
  return sqrt(x*x+y*y);
}
 
inline void add(int u,int v,double l)
{
  e[++cnt].to=v;e[cnt].l=l;
  e[cnt].nxt=ehead[u];ehead[u]=cnt;
}
 
inline void prework()
{
  scanf("%d%d",&w,&n);
  for(int i=1;i<=3*n+2;i++)
    ehead[i]=0;
  S=3*n+1;T=3*n+2;
  for(int i=1;i<=n;i++)
      scanf("%d%d",&a[i].x,&a[i].y);
  for(int i=1;i<=n;i++)
    {
      a[n+i].x=0,a[n+i].y=a[i].y;
      add(S,n+i,0);
      add(n+i,i,a[i].x);
      a[2*n+i].x=w;a[2*n+i].y=a[i].y;
      add(T,2*n+i,0);
      add(2*n+i,i,w-a[i].x);
    }
  double l;
  for(int i=1;i<=n;i++)
    for(int j=i+1;j<=n;j++)
      {
	l=dist(a[i].x-a[j].x,a[i].y-a[j].y);
	add(i,j,l);add(j,i,l);
      }
}
 
inline void dfs1(int u,double mid)
{
  int v;visS[u]=true;
  for(int i=ehead[u];i;i=e[i].nxt)
    if(e[i].l<mid+eps)
      {
	v=e[i].to;
	if(!visS[v])
	  dfs1(v,mid);
      }
}
 
inline void dfs2(int u,double mid)
{
  int v;visT[u]=true;
  for(int i=ehead[u];i;i=e[i].nxt)
    if(e[i].l<mid+eps)
      {
	v=e[i].to;
	if(!visT[v])
	  dfs2(v,mid);
      }
} 
 
inline bool jug(double mid)
{
  for(int i=1;i<=3*n+2;i++)
    visS[i]=false,visT[i]=false;
  dfs1(S,mid);
  dfs2(T,mid);
  for(int i=1;i<=3*n;i++)
    for(int j=1;j<=3*n;j++)
      if(visS[i] && visT[j])
	{
	  if(dist(a[i].x-a[j].x,a[i].y-a[j].y)<=2*mid+eps)
	    {
	      ansx=(1.0*a[i].x+a[j].x)/2;
	      ansy=(1.0*a[i].y+a[j].y)/2;
	      return true;
	    }
	}
  return false;
}
 
inline void mainwork()
{
  if(n==0)
    {
      ansx=1.0*w/2;ansy=0;
      return;
    }
  double l=0,r=w,mid;
  while(l+eps<r)
    {
      mid=(l+r)/2;
      if(jug(mid))
	r=mid;
      else
	l=mid;
    }
}
 
inline void print()
{
  printf("%.3f %.3f",ansx,ansy);
}
 
int main()
{
  freopen("froggy.in","r",stdin);
  freopen("froggy.out","w",stdout);
  prework();
  mainwork();
  print();
  return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值