Skip to main content Link Menu Expand (external link) Document Search Copy Copied

07694번 Triangle

Problem link: https://www.acmicpc.net/problem/7694

Keywords: Geometry, Pick's Theorem

이 블로그에서는 시간이 날 때마다 이전 블로그에서 풀었던 문제들을 다시 풀어서 정리하고 있다. 그런데, 그새 조금 더 늙었기 때문인지 업데이트가 참 더디다. 아마도, 대학 시절에는 없었던 결혼생활과 두 아이의 육아라는 과업이 영향이 있는 것 같다. 그래서, 뭔가 처방이 필요하지 않나라는 생각을 해보았다. 결정한 처방은 “그냥 재미있는 것 풀자” 이다.

나는 대학교 때부터 computational geometry나 graph theory를 참 좋아했었다. 하지만, acmicpc나 코딩 인터뷰에서 해당 분야의 알고리즘을 출제하는 경우는 극히 드물 수 밖에 없음을 교활하게도 깨닫고 있었고, 따라서 자연스레 다른 재미 없어하는 알고리즘들에 집중했던 것 같다. 이제는 acmicpc나 코딩 인터뷰를 준비하는 것도 아니고, 회사 스트레스를 풀려고 문제를 풀고 있으니 그냥 좋아하던 것을 풀어보련다.

이 문제는 Pick’s Theorem을 쓰면 쉽게 풀 수 있다.

다만, Pick's Theorem을 사용하기 위해서 아래 bullet의 helper function들이 필요한데 크게 어렵지는 않으니 쉽게 구현할 수 있다.

  • Triangle의 넓이 구하기
    • 각 변을 순서대로 순회하면서 외적의 합을 구하고, 그 절대값의 절반을 취해주면 된다.
  • Triangle의 exterior에 있는 격자점 수 구하기
    • 최대공약수를 잘 활용해주면 역시 쉽게 풀 수 있다.

아래는 솔루션이다.

#include <cmath>
#include <iostream>
#include <vector>

using namespace std;

// Inputs.
struct Point2D {
  int x;
  int y;
};

struct Polygon2D {
  vector<Point2D> exterior;
};

// Solution.
int ComputeGcd(int a, int b) {
  while (b != 0) {
    int r = a % b;
    a = b;
    b = r;
  }
  return a;
}

double ComputeArea(const Polygon2D& polygon) {
  double sum = 0.0;
  for (std::size_t idx = 0; idx < polygon.exterior.size(); ++idx) {
    const auto& from = polygon.exterior[idx];
    const auto& to = polygon.exterior[(idx + 1) % polygon.exterior.size()];
    sum += from.x * to.y - from.y * to.x;
  }
  return 0.5 * abs(sum);
}

int CountLatticePointsOnExterior(const Polygon2D& polygon) {
  int ret = 0;
  for (std::size_t idx = 0; idx < polygon.exterior.size(); ++idx) {
    const auto& from = polygon.exterior[idx];
    const auto& to = polygon.exterior[(idx + 1) % polygon.exterior.size()];
    const auto dx = abs(from.x - to.x);
    const auto dy = abs(from.y - to.y);
    if (dx == 0) {
      ret += dy;
    } else if (dy == 0) {
      ret += dx;
    } else {
      auto gcd = ComputeGcd(dx, dy);
      ret += dx / (dx / gcd);
    }
  }
  return ret;
}

int Solution(const Polygon2D& polygon) {
  double area = ComputeArea(polygon);
  int lattice_points_on_exterior = CountLatticePointsOnExterior(polygon);
  return static_cast<int>(area - lattice_points_on_exterior / 2 + 1);
}

int main(void) {
  // For faster IO.
  ios_base::sync_with_stdio(false);
  cout.tie(nullptr);
  cin.tie(nullptr);

  // Read inputs.
  while (true) {
    Polygon2D polygon3};
    cin >> polygon.exterior[0].x >> polygon.exterior[0].y >>
        polygon.exterior[1].x >> polygon.exterior[1].y >>
        polygon.exterior[2].x >> polygon.exterior[2].y;
    if (polygon.exterior[0].x == 0 && polygon.exterior[0].y == 0 &&
        polygon.exterior[1].x == 0 && polygon.exterior[1].y == 0 &&
        polygon.exterior[2].x == 0 && polygon.exterior[2].y == 0) {
      break;
    } else {
      // Solve.
      cout << Solution(polygon) << '\n';
    }
  }

  return 0;
}