Summer Training 06 - Amritapuri 2012 总结
题意:
给定n只蚂蚁在二维平面上的坐标,并且知道蚂蚁的速度,蚂蚁直线前进,找一个点,使得最迟到达这个点的蚂蚁花费的时间最小。
解法:
二分到达的时间t,蚂蚁可以到达的范围是以它最初位置为圆心,t×v为半径的圆,如果这些圆都相交于某块地方,则表示当前的t可行,减小继续二分
//Memory: 3277 KB
//Time: 1070 MS
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <iostream>
using namespace std;
const int MAXN = 105;
const double EPS = 1e-8;
const double INF = 1e30;
const double PI = acos(-1.0);
int dcmp(double x)
{
if(fabs(x)<EPS) return 0;
return x<0?-1:1;
}
struct Point{
double x,y;
double pa;
int cnt;
Point(){}
Point(double a,double b):x(a),y(b){}
Point(double a,double b,double c,int d):x(a),y(b),pa(c),cnt(d){}
Point operator +(Point a)const{return Point(x+a.x,y+a.y);}
Point operator -(Point a)const{return Point(x-a.x,y-a.y);}
bool operator <(const Point &a)const
{
return pa<a.pa;
}
void input(){scanf("%lf%lf",&x,&y);}
};
typedef Point Vector;
struct Circle{
Point c;
double r;
bool flag;
Point point(double x)
{
return Point(c.x+cos(x)*r,c.y+sin(x)*r);
}
};
double Cross(Vector a,Vector b)
{
return a.x*b.y-a.y*b.x;
}
double Dot(Vector a,Vector b)
{
return a.x*b.x+a.y*b.y;
}
double Length(Vector a)
{
return sqrt(Dot(a,a));
}
double Angle(Vector v)
{
return atan2(v.y,v.x);
}
Point p[MAXN],e[MAXN];
int cover[MAXN];
double s[MAXN];
bool Getccinte(Circle c1,Circle c2,Point &a,Point &b)
{
double d = Length(c1.c-c2.c);
if(dcmp(d)==0||dcmp(c1.r+c2.r-d)<0||dcmp(fabs(c1.r-c2.r)-d)>0)
return 0;
double ang = Angle(c2.c-c1.c);
double da = acos((c1.r*c1.r+d*d-c2.r*c2.r)/(2*c1.r*d));
a = c1.point(ang-da),b = c1.point(ang+da);
return 1;
}
bool circle_union(int n,Circle c[],double s[])
{
Point a,b;
for(int i = 0; i <=n; i++) s[i] = 0;
for(int i = 0; i < n; i++)
for(int j = 0; j < n; j++)
{
double d = c[i].r-c[j].r;
if(i!=j&&dcmp(d)>0&&dcmp(Length(c[i].c-c[j].c)-d)<=0)
cover[j]++;
}
for(int i = 0; i < n; i++)
{
int en = 0;
e[en++] = Point(c[i].c.x-c[i].r,c[i].c.y,-PI,1);
e[en++] = Point(c[i].c.x-c[i].r,c[i].c.y,PI,-1);
for(int j = 0; j < n; j++)
{
if(i==j) continue;
if(Getccinte(c[i],c[j],a,b))
{
e[en++] = Point(a.x,a.y,atan2(a.y-c[i].c.y,a.x-c[i].c.x),1);
e[en++] = Point(b.x,b.y,atan2(b.y-c[i].c.y,b.x-c[i].c.x),-1);
if(dcmp(e[en-2].pa-e[en-1].pa)>0)
{
e[0].cnt++;
e[1].cnt--;
}
}
}
sort(e,e+en);
int cnt = e[0].cnt;
for(int j = 1; j < en; j++)
{
double pad = e[j].pa-e[j-1].pa;
s[cover[i]+cnt] += (Cross(e[j-1], e[j])+c[i].r*c[i].r*(pad-sin(pad)))/2;
cnt += e[j].cnt;
if(dcmp(s[n])>0) return 1;
}
}
//cout<<s[n-1]<<endl;
return 0;
}
double v[MAXN];
int main()
{
//freopen("F:\\acmcode\\in.txt","r",stdin);
int cas,tmp;
int n,cnt;
bool flag;
Circle c[MAXN];
Point sol[MAXN*MAXN][2];
scanf("%d",&cas);
while(cas--)
{
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
p[i].input();
c[i].c = p[i];
c[i].flag = 1;
scanf("%lf",&v[i]);
}
double l,r,m,ans=0;
l = 0,r = INF;
while(r-l>EPS)
{
flag = 1;
m = (l+r)/2;
cnt = 0;
for(int i = 0; i < n; i++)
c[i].r = m*v[i];
memset(cover,0,sizeof(cover));
if(circle_union(n,c,s)) ans = m, r = m-EPS;
else l = m+EPS;
}
printf("%.6lf\n",ans);
}
return 0;
}