C++で座標の集合から作れる長方形の最小面積を求める方法
問題の概要
XY平面上にいくつかの点が与えられたとします。これらの点から作ることができる長方形のうち、面積が最小になるものを求めます。ただし、長方形の各辺はX軸およびY軸と平行でなければならず、長方形が構成できない場合は0を返します。
例えば、点の集合が [(1, 1), (1, 3), (3, 1), (3, 3), (2, 2)] の場合、(1, 1)、(1, 3)、(3, 1)、(3, 3) の4点を使って長方形を作れるため、答えは4となります。
解法の考え方
この問題を効率よく解くには、まず点をx座標ごとに整理し、同じ縦の直線上にある点同士をグループ化します。続いて、各グループ内の点のペア(例:(x, y1) と (x, y2))に注目し、このペアを長方形の右側の辺として利用できる最小の長方形を探します。
そのために、それまでに処理した「y座標のペア」と、そのペアが最後に現れたx座標を記録しておきます。同じペア (y1, y2) が過去の別のx座標でも見つかっていれば、2つのx座標を左右の辺、y1とy2を上下の辺とする長方形が確定します。このときの面積は (現在のx − 前回のx) × (y2 − y1) で計算でき、すべての候補を調べながら最小値を更新していきます。最終的に、得られた長方形の面積の最小値を返します。
アルゴリズムの手順
- すべての点をx座標ごとに分類し、各x座標に紐づくy座標のリストを作成する
- x座標を昇順にソートしながら各列を走査する
- 各列の中で、y座標のすべてのペア (y1, y2) を列挙する
- 同じペアが以前のx座標で記録されていれば、面積 (x − 前回のx) × (y2 − y1) を計算し、最小値を更新する
- 現在のペアに対して最新のx座標を記録し、処理を続ける
C++による実装例
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>
#include <climits>
using namespace std;
int findMinArea(vector<vector<int>>& points) {
// x座標ごとにy座標をグループ化
map<int, vector<int>> columns;
for (const auto& p : points) {
columns[p[0]].push_back(p[1]);
}
// ペア (y1, y2) が最後に現れたx座標を記録
map<pair<int, int>, int> lastx;
long long ans = LLONG_MAX;
for (const auto& [x, col] : columns) {
vector<int> sortedCol = col;
sort(sortedCol.begin(), sortedCol.end());
for (size_t j = 0; j < sortedCol.size(); ++j) {
for (size_t i = 0; i < j; ++i) {
pair<int, int> key = {sortedCol[i], sortedCol[j]};
auto it = lastx.find(key);
if (it != lastx.end()) {
long long area =
(long long)(x - it->second) * (key.second - key.first);
ans = min(ans, area);
}
lastx[key] = x;
}
}
}
return (ans == LLONG_MAX) ? 0 : static_cast<int>(ans);
}
int main() {
vector<vector<int>> points = {{1, 1}, {1, 3}, {3, 1}, {3, 3}, {2, 2}};
cout << "Minimum area of rectangle: " << findMinArea(points) << endl;
return 0;
}
実行結果
Minimum area of rectangle: 4
計算量の目安
点の総数をNとすると、x座標ごとのグループ化とソートにはO(N log N)、各列内でのy座標ペアの列挙には最悪の場合O(N²)の時間がかかります。必要なメモリはO(N)程度です。点の配置によっては実際の計算量は大きく抑えられるため、実用的な速度で動作します。
-
C++で点集合から単純な閉じた経路(閉路)を求めるアルゴリズム
平面上に与えられた点の集合があり、そのすべての点をちょうど一度ずつ通る「単純な閉じた経路(単純閉路)」を見つけたいとします。下の図のような点が与えられた場合、これらの点を適切な順序で結ぶことで閉じたパスを構成できます。 アルゴリズムの考え方 この問題は、凸包を求める際に用いられる「偏角ソート」の考え方を応用することで解くことができます。具体的な手順は以下の通りです。 最も左下にある点(y座標が最小、同一の場合はx座標も最小)を基準点 P として選びます。 残りの n − 1 個の点を、P を中心とした反時計回りの偏角(極角)に基づいてソートします。2つの点の偏角が等しい場合は、P からの
-
C++で中点の座標を使って長方形の4つの頂点を求める方法
問題の概要長方形 ABCD があり、その中点 P と Q の座標、および長方形の辺の長さ L のみが分かっているとします。この課題の目的は、P と Q の座標および辺の長さ L を使って、頂点 A、B、C、D の座標を求めることです。例えば、P が (1, 0)、Q が (1, 2)、L が 2 の場合、A、B、C、D はそれぞれ (0, 0)、(0, 2)、(2, 2)、(2, 0) となります。考えられる3つの場合P と Q の位置関係によって、次の3つの場合が考えられます。長方形が水平な場合:AD と BC が X 軸に平行長方形が垂直な場合:AD と BC が Y 軸に平行長方形が軸に