GitHub - jzplp/aoapc-UVA-Answer: 算法竞赛入门经典 例题和习题答案 刘汝佳 第二版
这道题目我做的有点困难,主要是做浮点数有关的题目不多,且基本没做过这种角度有关的题目,因此处理过程很容易漏下或者出错。
还是使用算法竞赛入门经典书中的方法,遍历n个点,每个点都作为一次零点,转换所有点的坐标系。然后对这些点按照向量的角度排序。注意浮点数排序函数不能直接返回 角度-角度,浮点数这样是不支持的。
排序后遍历一圈。拿到0-180,180-360,以及在 0 180线上的点的个数。
0 180线作为起始线,按照角度每个点向前前进,再遍历一圈。计算出按照零点和当前点作为线计算得到的数字。最后输出最大数字。
最后这次遍历实际上只需要遍历半圈,但是需要 0 -180 和 180 -360 同时进行,那边点转动的角度小,就转哪边。还要注意向前查看是否有同角度的点,也需要一起加进来。
一开始我为了简单做,最后一次遍历没有遍历半圈,而是遍历一整圈。这样另外一侧就不是一次向前一个点,而是可能向前很多点。后来我发现这样做情况复杂,甚至有可能一转超过半圈,叫哦都计算也很困难,于是改成了现在的做法。
另外我计算点相等时,用的10e-8是WA的,10e-9才AC。
AC代码
cpp
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#define MIN_DIFF 10e-9
struct Item
{
int x, y;
int t;
double angle;
};
// 原始数据
Item arrOrigin[1010];
int n;
Item arr[1010];
int compare(const void *left, const void *right)
{
if (((const Item *)left)->angle > ((const Item *)right)->angle)
return 1;
if (((const Item *)left)->angle < ((const Item *)right)->angle)
return -1;
return 0;
}
bool getEqualAngle(double angle1, double angle2)
{
return abs(fmod(angle1 - angle2 + 2 * M_PI, 2 * M_PI)) < MIN_DIFF;
}
// 预处理,变为以a点做起点
void preI(int a)
{
int i, j = 0;
int x = arrOrigin[a].x, y = arrOrigin[a].y;
for (i = 0; i < n; ++i)
{
if (i == a) // 去掉原点本身
continue;
// 以第a个点为零点转换坐标系
arr[j].x = arrOrigin[i].x - x;
arr[j].y = arrOrigin[i].y - y;
arr[j].t = arrOrigin[i].t;
// 求atan2角度,最小角度0
arr[j].angle = fmod(atan2(arr[j].y, arr[j].x) + 2 * M_PI, 2 * M_PI);
++j;
}
// 从小到大排序
qsort(arr, n - 1, sizeof(Item), compare);
}
int getRes(int topWhite, int topBlack, int bottomWhite, int bottomBlack, int line)
{
int res1 = topWhite + bottomBlack;
int res2 = topBlack + bottomWhite;
return (res1 > res2 ? res1 : res2) + 1 + line;
}
// 计算
int computedI()
{
int i, j, i1 = 0, i2 = 0, j1 = 0, j2 = 0, ii, jj;
bool flag = false;
double ai, aj, a;
int topWhite = 0, topBlack = 0, bottomWhite = 0, bottomBlack = 0, lineLeftWhite = 0, lineLeftBlack = 0, lineRightWhite = 0, lineRightBlack = 0;
int maxRes = 0, res;
// 计算起始个数
// 计算0-180度的数量(不含180)
for (i = 0; i < n - 1; ++i)
{
if (arr[i].angle < MIN_DIFF)
{
if (arr[i].t)
++lineLeftWhite;
else
++lineLeftBlack;
continue;
}
if (abs(arr[i].angle - M_PI) < MIN_DIFF || arr[i].angle > M_PI)
break;
if (arr[i].t)
++topWhite;
else
++topBlack;
}
i1 = lineLeftWhite + lineLeftBlack;
i2 = i;
// 计算180-360度的数量(含180)
for (; i < n - 1; ++i)
{
if (abs(arr[i].angle - M_PI) < MIN_DIFF)
{
if (arr[i].t)
++lineRightWhite;
else
++lineRightBlack;
j1 = i + 1;
continue;
}
if (abs(arr[i].angle - 2 * M_PI) < MIN_DIFF)
{
if (!flag)
{
j2 = i;
flag = true;
}
if (arr[i].t)
++lineLeftWhite;
else
++lineLeftBlack;
continue;
}
if (arr[i].t)
++bottomWhite;
else
++bottomBlack;
}
maxRes = getRes(topWhite, topBlack, bottomWhite, bottomBlack, lineLeftWhite + lineLeftBlack + lineRightWhite + lineRightBlack);
// 准备工作结束,开始遍历
i = i1;
j = j1 ? j1 : i2;
j2 = flag ? j2 : (n - 1);
while (i < i2 && j < j2)
{
topWhite += lineRightWhite;
topBlack += lineRightBlack;
bottomWhite += lineLeftWhite;
bottomBlack += lineLeftBlack;
lineRightWhite = 0;
lineRightBlack = 0;
lineLeftWhite = 0;
lineLeftBlack = 0;
ai = arr[i].angle;
aj = arr[j].angle;
if (ai + M_PI < aj)
a = ai;
else
a = aj - M_PI;
ii = i;
jj = j;
while (abs(arr[ii].angle - a) < MIN_DIFF && ii < i2)
{
if (arr[ii].t)
{
++lineLeftWhite;
--topWhite;
}
else
{
++lineLeftBlack;
--topBlack;
}
++ii;
}
while (abs(arr[jj].angle - a - M_PI) < MIN_DIFF && jj < j2)
{
if (arr[jj].t)
{
++lineRightWhite;
--bottomWhite;
}
else
{
++lineRightBlack;
--bottomBlack;
}
++jj;
}
i = ii;
j = jj;
res = getRes(topWhite, topBlack, bottomWhite, bottomBlack, lineLeftWhite + lineLeftBlack + lineRightWhite + lineRightBlack);
if (res > maxRes)
maxRes = res;
}
while (i < i2)
{
topWhite += lineRightWhite;
topBlack += lineRightBlack;
bottomWhite += lineLeftWhite;
bottomBlack += lineLeftBlack;
lineRightWhite = 0;
lineRightBlack = 0;
lineLeftWhite = 0;
lineLeftBlack = 0;
ii = i;
a = arr[i].angle;
while (abs(arr[ii].angle - a) < MIN_DIFF && ii < i2)
{
if (arr[ii].t)
{
++lineLeftWhite;
--topWhite;
}
else
{
++lineLeftBlack;
--topBlack;
}
++ii;
}
i = ii;
res = getRes(topWhite, topBlack, bottomWhite, bottomBlack, lineLeftWhite + lineLeftBlack + lineRightWhite + lineRightBlack);
if (res > maxRes)
maxRes = res;
}
while (j < j2)
{
topWhite += lineRightWhite;
topBlack += lineRightBlack;
bottomWhite += lineLeftWhite;
bottomBlack += lineLeftBlack;
lineRightWhite = 0;
lineRightBlack = 0;
lineLeftWhite = 0;
lineLeftBlack = 0;
jj = j;
a = arr[j].angle;
while (abs(arr[jj].angle - a) < MIN_DIFF && jj < j2)
{
if (arr[jj].t)
{
++lineRightWhite;
--bottomWhite;
}
else
{
++lineRightBlack;
--bottomBlack;
}
++jj;
}
j = jj;
res = getRes(topWhite, topBlack, bottomWhite, bottomBlack, lineLeftWhite + lineLeftBlack + lineRightWhite + lineRightBlack);
if (res > maxRes)
maxRes = res;
}
return maxRes;
}
int computed()
{
int i, j, k;
int maxRes = 0, res;
for (i = 0; i < n; ++i)
{
preI(i);
res = computedI();
if (res > maxRes)
maxRes = res;
}
return maxRes;
}
int main()
{
int i, j;
while (scanf("%d", &n) > 0 && n > 0)
{
for (i = 0; i < n; ++i)
scanf("%d %d %d", &arrOrigin[i].x, &arrOrigin[i].y, &arrOrigin[i].t);
printf("%d\n", computed());
}
return 0;
}