【C++】n個の点のうちm個が同一直線上にあるときに作れる三角形の数を求める方法
問題の概要
2次元平面上の点の総数を表す2つの変数 n と m が与えられます。このうち m 個の点は同一直線上(コリニア)に並んでいます。ここでの課題は、これら n 個の点から作ることができる三角形の数を求めることです。
同一直線上の点(共線点)とは、同じ一本の直線上に乗っている点のことです。例えば下図では、点 A と点 B が同一の直線上に位置しています。
考え方の基本
まず、n=4(A, B, C, D)、m=2(A, B)という具体例で確認してみましょう。
三角形の数は次の手順で計算できます。
・4 点から任意の 3 点を選ぶ組み合わせ = 4C3
・ただし、同一直線上の点だけでは三角形が成立しないため、先の計算に含まれる無効な組み合わせを差し引く = 2C3
・合計 = 4C3 − 2C3 = 4 − 0 = 4(ABC、ACD、BCD、ABD)
これを一般化すると、答えは次の公式で表せます。
三角形の数 = nC3 − mC3
入力例と出力例
入力:n=5、m=3
出力:9
解説:5C3 − 3C3 = 10 − 1 = 9
入力:n=10、m=5
出力:110
解説:10C3 − 5C3 = 120 − 10 = 110
プログラムで使うアプローチ
組み合わせの計算を効率的に行うために、パスカルの三角形を利用します。各行は、前の行の隣り合う列同士を足し合わせることで順に求められます。処理の流れは以下の通りです。
- 点の数として変数 n と m を入力します。
- 関数 collinear_points(int n, int m) が n と m を受け取り、m 個が同一直線上にある n 点から作れる三角形の数を返します。
- count = check(n, 3) − check(m, 3) として、nC3 − mC3 を計算します。
- 関数 check(int n, int r) は n と r を受け取り、nCr の値を返します。
- 長さ r+1 の配列 arr を用意します。
- memset を使って配列全体を 0 で初期化します。
- arr[0] = 1 を設定します。
- i=0〜n、j=min(i,r)〜j>0 の二重ループでパスカルの三角形を構築し、arr[j] = arr[j] + arr[j-1] と更新していきます。
- 最終的に arr[r] が nCr の値となるので、それを返します。
- check() の処理が完了すれば、三角形の数が求められます。
- count を結果として返します。
この手法の計算量は O(n × r) であり、階乗を直接計算する方法と比べてオーバーフローのリスクを抑えつつ安定して組み合わせを求められるのが利点です。
C++実装例
#include <bits/stdc++.h>
using namespace std;
int check(int n, int r){
int arr[r+1];
memset(arr, 0, sizeof(arr));
arr[0] = 1;
for (int i = 1; i <= n; i++){
for (int j = min(i, r); j > 0; j--){
arr[j] = arr[j] + arr[j-1];
}
}
return arr[r];
}
int collinear_points(int n,int m){
int count = check(n, 3) - check(m, 3);
return count;
}
int main(){
int n = 6, m = 2;
cout<<"n個の点のうちm個が同一直線上にある場合に作れる三角形の数: "<< collinear_points(n, m);
return 0;
}出力
上記のコードを実行すると、次の出力が得られます。
n個の点のうちm個が同一直線上にある場合に作れる三角形の数: 20
この結果は、6C3 − 2C3 = 20 − 0 = 20 となり、公式どおりの値が正しく求まっていることが分かります。
-
C++でk個の等間隔点を持つ円における、指定した2点間の鈍角の数を求める方法
円周上にK個の等間隔(等距離)の点が配置された円が与えられます。さらに、2つの点AとBも与えられます。この記事の目的は、これらの点を使って構成できる三角形のうち、内部に90度より大きい鈍角ACBを持つものの数を数えることです。点AとBは常に A < B を満たすものとします。下図の例では K=8、A=2、B=5 であり、∠ACB および ∠AC′B が鈍角になるような点は C と C′ の2つ存在します。具体例で理解しよう入力 − k=10、A=2、B=4出力 − 2つの指定点間にk個の等間隔点を持つ円における鈍角の数 − 1説明 − 条件を満たす点は C=3 のみです。入力 − k=1
-
【C++】aの個数がbより多い部分文字列の総数を効率的に求める方法
この問題では、文字 a と b のみで構成された文字列 str と整数 N が与えられます。str を N 回繰り返して連結することで新しい文字列を作成し、その中に含まれる「a の出現回数が b より多い」部分文字列の総数を求めて出力するのが課題です。 問題の例 まず、具体的な例で問題を確認してみましょう。 入力: aab 2 出力: 9 説明: 作成された文字列は aabaab。 条件を満たす部分文字列: a, aa, aab, aaba, aabaa, aabaab, aba, baa, abaa 解法のアプローチ この問題を解くには、毎回完全な文字列を生成するのではなく、元の文字列 st