Fruit Slicer
Problem Description
John, a student who is taking the game development course, recently developed a mobile game called Fruit Slicer for his coursework. In the game the player slices fruits that are throw into the air by swiping the touch screen. However the game is quite simple because John was not able to write code for the geometry required for a more complex version. In the game each slice is a straight line of infinite length, and all fruits have the same shape of a circle with unit ra- dius. The figure shows a cool snapshot of John’s game.
John introduces his game to his best friend Sean, who soon gets bored of playing the simple game. But as a teaching assistant of the algorithm course, Sean decides to turn the
game into a homework assignment. He asks the students in the algorithms course to write a program that can compute the best slice at any given moment of the game. Given the locations of the fruits, the program should determine the maximum number of fruits that can be sliced with a single straight-line swipe.
As a student in Sean’s class, you are now the one who is facing this challenge.
Input
The first line has a single integer n (1 ≤ n ≤ 100). The next n lines each have two real numbers giving the x and y coordinates of a fruit. All coordinates have an absolute value no larger than 10410^4104 and are given with exactly two digits after the decimal point. Fruits may overlap.
Output
Output the maximum number of fruits that can be sliced with one straight-line swipe. A swipe slices a fruit if the line intersects the inner part or the boundary of the fruit.
Sample Input
5
1.00 5.00
3.00 3.00
4.00 2.00
6.00 4.50
7.00 1.00
Sample Output
4
Sample Input2
3
-1.50 -1.00
1.50 -1.00
0.00 1.00
Sample Output2
3
Sample Input3
2
1.00 1.00
1.00 1.00
Sample Output3
2
Brief Description
确定单个直线能够最多与多少个单位元相交或者相切
Solution
我们知道,始终存在与两个圆相切的最佳线。
O(n2)枚举圆对,找出他们公切线,并为每个线性检查它相交或接触的圆的个数,更新最大值。
被浮点数精度折磨的要死,Debug4小时不是吹的,
题解给的是,只需要对系数*100,把所有开根号的比较转换为平方的比较,就可以用int做了
杂乱未加整理的代码:
#include <iostream>
#include <cmath>
double const PI = acos(-1);
using namespace std;
struct Point{
double x,y;
//Point(double x=0,double y=0):x(x),y(y){}
};
typedef Point Vector;
Vector operator + (Vector A,Vector B){
return Vector{A.x+B.x,A.y+B.y};
}
Vector operator - (Vector A,Vector B){
return Vector{A.x-B.x,A.y-B.y};
}
Vector operator * (Vector A,double p){
return Vector{A.x*p,A.y*p};
}
Vector operator / (Vector A,double p){
return Vector{A.x/p,A.y/p};
}
bool operator < (const Point& a,const Point& b){
return a.x<b.x||(a.x==b.x&&a.y<b.y);
}
struct Line{
Vector v;
Point p;
};
struct Circle{
Point c;
double r;
//Circle(Point c,double r):c(c),r(r){}
//Point point(double a){
// return Point(c.x+cos(a)*r,c.y+sin(a)*r);
//}
Point getPoint(double a){
//TODO:
return Point{c.x+cos(a)*r,c.y+sin(a)*r};
}
};
const double eps = 1e-6;
int dcmp(double x){
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
int dcmp2(double x){
if(fabs(x)<eps) return 0;
else return x<0?-1:1;
}
bool operator == (const Point& a,const Point& b){
return dcmp(a.x-b.x)==0&&dcmp(a.y-b.y)==0;
}
int getLineCircleIntersection(Line L,Circle C){
double a = L.v.x,b=L.p.x - C.c.x,c=L.v.y,d=L.p.y-C.c.y;
double e=a*a + c*c,f=2*(a*b+c*d),g=b*b+d*d-C.r*C.r;
double delta = f*f - 4*e*g;
if(dcmp2(delta)<0) return 0;
if(dcmp2(delta)==0) return 1;
return 2;
}
int getTangents(Circle A, Circle B, Point *a, Point *b){
if (A.c==B.c){
a[0]=A.c;
b[0]=A.getPoint(0);
return 1;
}
int cnt = 0;
//if(A.r < B.r){
// swap(A, B);
// swap(a,b);
//}
double d2 = (A.c.x-B.c.x)*(A.c.x-B.c.x) + (A.c.y-B.c.y)*(A.c.y-B.c.y);
double rDiff = 0.0;
double rSum = 2.0;
//if(dcmp(d2 - rDiff*rDiff)<0) return 0;
double base = atan2(B.c.y - A.c.y, B.c.x - A.c.x);
//if(d2 == 0 && A.r == B.r) return -1;
// if(dcmp(d2 - rDiff*rDiff)==0){
// a[cnt] = A.getPoint(base);
// b[cnt] = B.getPoint(base);
// ++cnt;
// return 1;
// }
double ang = acos(0);
a[cnt] = A.getPoint(base + ang);
b[cnt] = B.getPoint(base + ang);
++cnt;
a[cnt] = A.getPoint(base - ang);
b[cnt] = B.getPoint(base - ang);
++cnt;
if(dcmp(d2 - 4.0) == 0){
a[cnt] = A.getPoint(base);
Vector t_v = A.c-B.c;
if(dcmp(t_v.y)==0){
b[cnt]= Point{a[cnt].x,a[cnt].y+1.0};
}
else{
b[cnt] = Point{a[cnt].x+1.0,a[cnt].y-t_v.x/t_v.y};
}
++cnt;
}
else if(dcmp(d2 - 4.0)>0){
double ang2 = acos((2.0)/sqrt(d2));
a[cnt] = A.getPoint(base + ang2);b[cnt] = B.getPoint(PI+base+ang2);++cnt;
a[cnt] = A.getPoint(base - ang2);b[cnt] = B.getPoint(PI+base-ang2);++cnt;
}
return cnt;
}
const int maxn = 105;
int n;
Point poi[maxn];
Circle cir[maxn];
int main(){
cin>>n;
double x,y;
for(int i=1;i<=n;i++){
cin>>x>>y;
poi[i].x=x;
poi[i].y=y;
cir[i].c.x=x;
cir[i].c.y=y;
cir[i].r=1.0;
}
Line l;
int ans=2,cnt,ct;
Point a[10],b[10];
for(int i=1;i<=n;i++){
for(int j=i+1;j<=n;j++){
//if(poi[i]==poi[j]) continue;
//l.v=(poi[i]-poi[j]);
//cout<<j<<endl;
ct=getTangents(cir[i],cir[j],a,b);//cout<<ct<<endl;
for(int d=0;d<ct;d++){
cnt=0;
l.v=(a[d]-b[d]);
l.v=l.v/sqrt(l.v.x*l.v.x + l.v.y*l.v.y);
l.p=b[d];
for(int k=1;k<=n;k++){
if(getLineCircleIntersection(l,cir[k])) cnt++;
//else
//cout<<a[d].x<<" "<<a[d].y<<"\n"<<b[d].x<<" "<<b[d].y<<endl;
}
ans=max(ans,cnt);//cout<<a[d].x<<" "<<a[d].y<<"\n"<<b[d].x<<" "<<b[d].y<<endl;
}
}
}
if(n==1) ans=1;
cout<<ans;
return 0;
}
/*
10
10000 10000
9999.99 9999.98
8888.98 8888.89
8888.99 8888.88
0.01 100.11
0.02 100.10
0.03 100.12
2.01 -100.99
2.02 -200.02
2.00 -9999.99
//cout<<a[d].x<<" "<<a[d].y<<"\n"<<b[d].x<<" "<<b[d].y<<endl;
2
45 23
789 11
2
5329.21 1848.86
3301.3 492.59
*/