这个是2011阿里巴巴程序设计公开赛中的一个题,我们用这套题打了一场组队赛,最后却输在了这个题上,其实看了解题报告http://hi.baidu.com/kerrynit/item/85c865090210ed0aebfe3872很好做,只是比赛时不容易证明这个思路。
摘自解题报告:
1002 Fruit Ninja
类型:几何(简单)
假设有一条线穿过一些水果,那么我们将这条线平移,使之与一水果的一个点相交,然后按这个点进行旋转,又可以使之与另一水果的一个点相交.这次这条线还是穿过这些水果.
所以,我们可以枚举两两水果的点做直线,然后计算该线穿过水果的个数
数据规模很小,随意随便搞.复杂度O(n^3*k^3).
#include<cstdio>
#include<cstring>
#include<iostream>
#define INF 0x7fffffff
using namespace std;
struct POINT
{
int x,y;
};
struct shape
{
int p;
POINT point[11];
};
shape sh[11];
int n;
int check(int k,int i,int j,int h,int m)
{
int ans=0;
if(k==INF)
{
for(int a=0; a<n; a++)
{
if(a==i||a==h) continue;
int flags=0,flagx=0;
for(int c=0; c<sh[a].p; c++)
{
if(sh[a].point[c].x<sh[i].point[j].x)
flags=1;
else if(sh[a].point[c].x>sh[i].point[j].x)
flagx=1;
else if(sh[a].point[c].x==sh[i].point[j].x)
flags=flagx=1;
if(flags==1&&flagx==1)
{
ans++;
break;
}
}
}
return ans;
}
double b=sh[i].point[j].y-k*sh[i].point[j].x;
for(int a=0; a<n; a++)
{
if(a==i||a==h) continue;
int flags=0,flagx=0;
for(int c=0; c<sh[a].p; c++)
{
double f=k*sh[a].point[c].x+b-sh[a].point[c].y;
if(flags==1&&flagx==1)
{
ans++;
break;
}
if(f>-1e-12&&f<1e-12)
{
flags=flagx=1;
}
else if(f>-1e-12)
flags=1;
else if(f<1e-12)
flagx=1;
}
}
return ans;
}
int main()
{
// freopen("in.txt","r",stdin);
int CASE,k;
cin>>CASE;
for(int cas=1; cas<=CASE; cas++)
{
cin>>n;
for(int i=0; i<n; i++)
{
cin>>k;
sh[i].p=k;
for(int j=0; j<k; j++)
{
int a,b;
cin>>a>>b;
sh[i].point[j].x=a,sh[i].point[j].y=b;
}
}
int maxx=0;
for(int i=0; i<n; i++)
{
for(int j=0; j<sh[i].p; j++)
{
for(int h=i+1; h<n; h++)
{
for(int m=0; m<sh[h].p; m++)
{
double x;
if(sh[i].point[j].x==sh[h].point[m].x)
x=INF;
else
x=(sh[i].point[j].y-sh[h].point[m].y)*1.0/(sh[i].point[j].x-sh[h].point[m].x);
int ans=check(x,i,j,h,m);
if(ans>maxx)
{
maxx=ans;
}
}
}
}
}
if(n<3)
cout<<"Case "<<cas<<": "<<n<<endl;
else
cout<<"Case "<<cas<<": "<<maxx+2<<endl;
}
return 0;
}