题意
平面上有n个点,每个点为白点或者黑点。现在需放置一条隔板,使得隔板一侧的白点数加上另一侧的黑点数总数最大。隔板上的点可以看做是在任意一侧。
思路
每次可以选取两个点作为隔板,所以我们可以先枚举一个基准点,然后算出其他点关于基准点的相对坐标和关于坐标系的极角(可以用atan2函数来计算,返回与x坐标值的角度),剩下的点依次与基准点形成分隔线,然后将一条直线绕基准点旋转,每当直线扫过一个点,就可以动态修改两侧的点数。
本题还有一个优化的方法,那就是如果该点是黑点,就可以将它的坐标关于基准点旋转180°,这样扫描时就只需要计算一侧的白点数了
代码分析(最后会贴lrj完整代码)
开始看lrj的书的时候发现有一个地方没看懂,如下:
int L = 0, R = 0, cnt = 2; //初始点数设为2,即分隔线上的两个点
while (L < k) //每个点都尝试与基点成为分割线
{
if (R == L) { R = (R + 1) % k; cnt++; } //空区域 **疑惑的地方**
while (R != L && left(p[L], p[R])) //R不等于L并且在180度之内
{
R = (R + 1) % k;
cnt++;
}
cnt--; //分隔线旋转,原本在分隔线上的点到了右边,所以要减去
L++; //分隔线旋转
ans = max(ans, cnt);
}
然后翻阅了一下博客,发现比较详细的博客中有详细的代码注释,但是没看到分析的地方,所以我自己思考后想