競プロで2つの格子点を通る直線を一意に表したい

競プロをやってると、2つの格子点(a, b), (c, d)を通る直線を考えたいことがよくあります。

そのときに、複数の直線集合の中から同一の直線をグルーピングしたい場合というのもよくあります。

そういうときに、同じ直線は同じ表現になり、異なる直線は異なる表現になるような表現があると便利です。

そういう方法を紹介します。

表現方法

簡単です。直線を、次のような形で表します。

  • ax + by + c = 0
  • ただし、gcd(a, b) = 1
  • (gcd(0, x) = gcd(x, 0) = x とする)

よくある直線の表現ですが、gcd(a, b) = 1という条件が加わっています。

この条件を加えることで、全ての(2つの格子点を通る)直線は一意に表すことができます。 (証明は省略します)

作り方

格子点(p, q), (r, s)を通る直線の表現を計算してみましょう。

まず、dx = r - p, dy = s - q とおくと、a = -dy, b = dx です。

すると、c = -a - b となります。

よって、(a, b, c) = (-dy, dx, -a - b) と求まりました。

使用例

(a, b, c)の値は直線によって一意なので、(a, b, c)をtupleにしてmapなどで持つと、いい感じに同一な直線のグルーピングができます。

例題: ABC220-G Isosceles Trapezium

法線を求める問題ですが、考え方は同じです。