UVA-1606 两亲性分子 题解答案代码 算法竞赛入门经典第二版

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;
}
相关推荐
Navigator_Z2 小时前
LeetCode //C - 1095. Find in Mountain Array
c语言·算法·leetcode
不会就选b2 小时前
算法日常・每日刷题--<二分查找>1
算法
Chen_harmony2 小时前
二、顺序表
数据结构
「維他檸檬茶」2 小时前
大模型算法学习2026.6.13
学习·算法
叫我:松哥2 小时前
基于Python的共享单车租赁数据分析与预测系统,技术栈flask+boostrap+随机森林+XGBoost
人工智能·python·深度学习·算法·随机森林·数据分析·flask
BAGAE2 小时前
星链卫星数据获取:从太空安全到实时通信的技术革命
网络·数据结构·数据库·算法·云计算·hbase
happymaker06262 小时前
LeetCodeHor100——438.找到字符串中所有的字母异位词
算法
西安邮电大学2 小时前
有关栈的经典算法题
java·后端·其他·算法·面试
h_a_o777oah3 小时前
【算法专项】扩展域并查集:原理详解及解决大部分种类并查集问题(洛谷P5937 P2024 C++代码)
数据结构·c++·算法·acm·并查集·扩展域·逻辑建模