ABC 218 D - Rectangles C++解答例
AtCoder Beginner Contest 218 D-RectanglesをC++で解きます。
更新履歴
- 2021/9/30:計算量の見積もりにおいて、
std::map
への各要素へのアクセスの計算量を考慮していなかったので修正しました。
問題
問題文をAtCoderのページより引用します。
問題文
2次元平面上に
個の相異なる点があり、 N の番号がついています。点 1, 2, \ldots, N の座標は i (1 \leq i \leq N) です。 (x_i, y_i) これらの点のうち4つを頂点とし、全ての辺が
軸または x 軸に平行であるような長方形はいくつありますか? y
制約
4 \leq N \leq 2000 0 \leq x_i, y_i \leq 10^9 (x_i, y_i) \neq (x_j, y_j) (i \neq j) - 入力はすべて整数である。
解答例
愚直に考えるとTLE
長方形を作るためには頂点が4つ必要になりますが、
選ぶ点を3つに減らしても
選ぶ点を2つにまで減らせたら何とか間に合いそうです。
対角にある点を考える
視点を変えて考えてみます。「全ての辺が
例えば、長方形の左上の頂点にあたる点と、右下の頂点にあたる点を決めれば、自ずと左上と右下の頂点も決まります。
従って、「
「長方形が作れるか?」を素早く判定する
対角になる2点
ここで全探索を使ってしまうと、せっかく探索候補を
高速な判定方法を探してみましょう。
ここで、「
つまり、ある点とstd::set
)で管理できるということがわかります。
集合で管理できるならば、存在するかどうかの判定は
実装の仕方
2次元平面上の各
std::set
を要素とする配列をとってもいいですが、制約からstd::map
を使いましょう。
std::map<int64_t, std::set<int64_t>>
型の変数を用意し、そこに点を記録していきます。std::map
の1つ目のキーが点の
そして、長方形の対角となる2点
- 直線
上にx = x_i 座標がy である点は存在するか?」y_j - 直線
上にx = x_j 座標がy である点は存在するか?」y_i
という2つの判定を行います。どちらも真であるならば、2点
この判定を全ての2点の組み合わせについて判定していけばよいです。
同じ長方形が2回計上されることに注意!
ここで1つ注意点があります。問題の条件を満たすある長方形について着目したとき、その長方形は対角となる点として「左下と右上の点の組」と「左上と右下の点の組」を持ちます。
そのため、
対策は簡単で、答えを出力するときに2で割ってやることで正しく計上することができます。
C++で実装した例
C++で実装した例が以下のコードです[1]。
map
へのアクセスを行い、更にそのそれぞれに対して集合の二分探索を行うので、総計算量は
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#include <map>
#include <set>
int main() {
int64_t N;
std::cin >> N;
std::vector<int64_t> x(N);
std::vector<int64_t> y(N);
std::map<int64_t, std::set<int64_t>> vertical_point;
for (int64_t i = 0; i < N; i++) {
int64_t px, py;
std::cin >> px >> py;
x.at(i) = px;
y.at(i) = py;
vertical_point[px].insert(py);
}
int64_t count = 0;
for (int64_t i = 0; i < N; i++) {
for (int64_t j = i; j < N; j++) {
if (x.at(i) != x.at(j) && y.at(i) != y.at(j)) {
if (vertical_point[x.at(i)].find(y.at(j)) != vertical_point[x.at(i)].end()
&& vertical_point[x.at(j)].find(y.at(i)) != vertical_point[x.at(j)].end())
{
count++;
}
}
}
}
std::cout << count / 2 << std::endl;
return 0;
}
実際に提出したコードはこちら。
-
2重ループの中に余計な判定(選んだ2点が相異なるかどうかチェックするif文)が入っちゃってます。多分無くても動きます ↩︎
Discussion