C++で垂直区間内の直線同士の交点を検出する方法
直線が y = mx + c という形式で複数本与えられているとします。これらの直線と垂直区間(縦方向の帯状領域)を考え、指定された区間内に直線同士の交点が存在するかどうかを判定します。例として、次のような直線があるとします。
L1 = y = x + 2
L2 = y = -x + 7
L3 = y = -3
L4 = y = 2x - 7
そして、垂直区間は x = 2 から x = 4 までとします。
この場合、L1 と L2 の交点はこの区間内に存在するため、答えは true となります。
解法の考え方
この問題は、ソートのテクニックを使うことで効率的に解けます。まず、各直線と垂直区間の両端(左境界・右境界)との交点を計算し、その結果をペアとして保存します。x座標は境界の値そのものと一致するため、保存が必要なのは交点のy座標だけです。
次に、これらのペアを「左境界でのy座標」を基準にソートします。その後、ペアを先頭から順に走査し、隣接する2つのペアを比較します。現在のペアの右境界でのy座標が、直前のペアの右境界でのy座標より小さくなっていたら、その垂直区間内に必ず交点が存在すると判断できます。
これは、区間内で交わる2本の直線は、左境界と右境界における上下の位置関係が入れ替わるという幾何学的な性質によるものです。
コード例
#include<iostream>
#include<algorithm>
#include<map>
using namespace std;
class line {
public:
int slope, intercept;
line(){
}
line(int slope, int intercept) : slope(slope), intercept(intercept) {
}
};
int getYCoordinate(line l, int x) {
return (l.slope * x + l.intercept);
}
bool hasIntersectionPoint(line lines[], int left_range, int right_range, int N) {
pair<int, int> y_border[N];
for (int i = 0; i < N; i++)
y_border[i] = make_pair(getYCoordinate(lines[i], left_range), getYCoordinate(lines[i], right_range));
sort(y_border, y_border + N);
for (int i = 1; i < N; i++) {
if (y_border[i].second < y_border[i - 1].second)
return true;
}
return false;
}
int main() {
int N = 4;
int slope[] = { 1, -1, 0, 2 };
int intercept[] = { 2, 7, -3, -7 };
line lines[N];
for (int i = 0; i < N; i++)
lines[i] = line(slope[i], intercept[i]);
int left_range = 2;
int right_range = 4;
if (hasIntersectionPoint(lines, left_range, right_range, N)) {
cout << "The intersection point is lies between " << left_range << " and " << right_range;
} else {
cout << "No intersection point is present in between " << left_range << " and " << right_range;
}
}出力
The intersection point is lies between 2 and 4
この出力から、交点が x = 2 から x = 4 の区間内に存在することが確認できます。
コードのポイント
line クラスは直線の傾き(slope)と切片(intercept)を保持します。getYCoordinate 関数は、指定したx座標における直線のy座標を返します。hasIntersectionPoint 関数では、まず全直線について左右の境界でのy座標をペア化し、ソートした上で順序の反転をチェックしています。計算量はソート処理が支配的で、全体の計算量は O(N log N) となります。
-
C++で2本の直線の交点を求めるプログラムの書き方
直線ABを定義する2点A・Bと、直線CDを定義する2点C・Dが与えられたとき、この2つの直線の交点を求めるのが課題です。 注意 − すべての点は、X座標とY座標を持つ2次元平面上にあるものとします。 図では、A(a1, a2)とB(b1, b2)を通る直線、C(c1, c2)とD(d1, d2)を通る直線という、互いに異なる2つの直線が描かれており、P(p1, p2)がその交点を表しています。 交点の求め方 まず、2点を通る直線を「ax + by = c」の形の方程式で表します。各点の座標を使って、次のように係数を計算します。 A1 = b2 - a2 B1 = a1 - b1 C1 =
-
C++で2つの等差数列の最初の衝突点(共通項)を求める方法
この記事では、2つの等差数列に共通して現れる最初の値――いわゆる「衝突点(コリジョンポイント)」――を見つけるC++プログラムについて解説します。問題の概要まず、5つの変数「a」「b」「c」「d」「n」が与えられます。これらの変数をもとに、それぞれn項からなる次の2つの等差数列(算術級数)を作成します。b, b+a, b+2a, …, b+(n−1)ad, d+c, d+2c, …, d+(n−1)cそのうえで、この2つの数列の両方に共通して含まれる最初の値を求めることが目的です。解法のアプローチこの問題は、次の手順で解くことができます。第1の数列の項を先頭から順に1つずつ生成します。生成した