今回は paiza の「「部外者をはじけ」を解くために:part5」の問題に挑戦!
問題概要
-
N人の座標データ (x_i, y_i ~ x_N, y_N)が与えられる -
最初の2人の位置を結ぶ直線を求め、
その直線から 2m以上離れている人(部外者) の数を出力する。
入力例:
20
331.26 330.83
264.31 3.44
118.56 118.09
162.59 162.15
329.92 330.36
271.86 272.05
371.44 371.42
340.22 340.48
286.67 286.36
466.66 466.17
407.49 407.67
381.02 381.45
271.05 270.96
39.97 39.84
464.65 464.65
352.98 352.62
260.1 260.41
31.92 31.92
476.45 139.5
184.83 185.22
出力例:
17
✅OK例:
const rl = require('readline').createInterface({ input: process.stdin });
const lines = [];
rl.on('line', (input) => lines.push(input));
rl.on('close', () => {
const N = Number(lines[0]); // 1行目は人数 N
// 2行目以降は座標データ
const points = lines.slice(1).map(line => line.split(' ').map(Number));
// 最初の2人の座標 (x1, y1), (x2, y2)
const [x1, y1] = points[0];
const [x2, y2] = points[1];
// 直線 ax + by + c = 0 の係数を計算
const a = y2 - y1;
const b = -(x2 - x1);
const c = (x2 - x1) * y1 - (y2 - y1) * x1;
let count = 0; // 部外者の人数カウント用
// 3人目以降の全員について距離を計算
for (const p of points.slice(2)) {
const [x, y] = p;
// 点と直線の距離を計算
const d = Math.abs(a * x + b * y + c) / Math.sqrt(a ** 2 + b ** 2);
// 距離が2m以上なら部外者としてカウント
if (d >= 2) count++;
}
// 部外者の数を出力
console.log(count);
});
🧩 コードの流れ
- 入力を受け取る準備
-
readlineで標準入力を行ごとにlines配列に保存。
-
- 入力完了後に処理開始
-
rl.on('close')で メインの処理を実行。
-
- データを取得
- 1行目:人数
N - 2行目以降:各人物の座標 (
x,y)
- 1行目:人数
- 最初の2点から直線の式を求める
- 係数
a,b,cを計算して、直線 ax + by + c = 0 の形を作る。
- 係数
- 残りの人との距離を計算
- 各点について距離公式
- "d = |ax + by + c| / √(a² + b²)" を使う。
- 距離が 2m 以上の人をカウント
-
if (d >= 2)で条件判定。
-
- 部外者の数を出力
-
console.log(count)で結果を表示。
-
📝まとめ
🧮 数学部分の理解
- 直線の方程式を2点 (x₁, y₁), (x₂, y₂) から求める:
- a = y₂ – y₁
- b = -(x₂ – x₁)
- c = (x₂ – x₁)y₁ – (y₂ – y₁)x₁
- → これで直線 ax + by + c = 0 の形を作る。
- 点と直線の距離を求める公式:
d = |ax + by + c| / √(a² + b²)
- 判定条件:
d ≥ 2 の人を「部外者」とする。
💻 プログラミング部分の理解
- 入力処理:
-
readlineで全行をlines配列に格納。 - 1行目 → 人数
N - 2行目以降 → 各人物の座標。
-
- 直線の係数
a,b,cを計算:- 最初の2人の座標を使って求める。
- 全員について距離を計算:
- 各点 (
x,y) に対して距離dを求め、 -
d ≥ 2の場合にcountを増やす。
- 各点 (
- 結果出力:
-
console.log(count)で部外者の人数を表示。
-