题意
给你一个平面上的n个点,有白点与黑点,问你怎么插入一个隔板使得隔板左右的黑白点数相加值最大。
思路
我们让隔板至少经过两个点,因为隔壁上的点属于左右两边的点,所以我们可以这么操作。我们枚举每个点,对于其他点建立与这个点的相对坐标,然后极角排序一发,接着就是枚举每两个点设置隔板,求隔板两边的黑白点数了。朴素的做法是我们设i为基准点,l为与i形成隔板的点,r为旋转点,我们让i与l不动,旋转r,旋转360度之后,就能求出黑白点了,然后取个max,接下来就是让l++,然后r又从l这个点开始继续旋转。
当然这里的优化很牛逼,首先我们将黑点对着基准点做中心对称,这样我们让r旋转180度的时候扫过的所有的点不就是分布在隔板两边的黑白点的和嘛!然后我们让l++,这时候r不需要再l进行扫描而是从原来的r继续旋转就可以了,这一点有点类似与移动一个区间!类似于尺取法。
#include <iostream>
#include <algorithm>
#include <cmath>
using namespace std;
int n;
const int MAXN=1000+5;
struct Point{
int x,y,col;
double angle;
}p[MAXN],p2[MAXN];
bool cmp(Point a,Point b)
{
return a.angle<b.angle;
}
bool cross(Point a,Point b)
{
return a.x*b.y-a.y*b.x>=0;
}
int main()
{
while(~scanf("%d",&n)&&n)
{
for(int i=0;i<n;i++) scanf("%d%d%d",&p[i].x,&p[i].y,&p[i].col);
int ans=0;
for(int i=0;i<n;i++)
{
int k=0;
for(int j=0;j<n;j++)
{
if(i==j) continue;
p2[k].x=p[j].x-p[i].x;
p2[k].y=p[j].y-p[i].y;
p2[k].col=p[j].col;
if(p2[k].col) p2[k].x=-p2[k].x,p2[k].y=-p2[k].y;
p2[k].angle=atan2(p2[k].y,p2[k].x);
k++;
}
sort(p2,p2+k,cmp);
int l=0,r=0,cont=2;
while(l<k)
{
if(l==r) {r=(r+1)%k,cont++;}
while(l!=r&&cross(p2[l],p2[r]))
{
r=(r+1)%k;
cont++;
}
cont--;
ans=max(ans,cont);
l++;
}
}
printf("%d\n",ans);
}
return 0;
}