cppAcademy
FROM LEARNING TO COMPETING

Proficient.
Put your skills to the test.

Bulgarian Informatics Group B · 2009–2026

217 independently explained problems: 54 Municipal, 54 Regional and 109 National. Start with the easier tasks and work upwards. Difficulty labels are learning estimates, not official ratings; Group B also includes challenging national-level problems. National-round tasks shared by Groups A and B are included. Years follow Arena’s competition-season labels. Source clarifications and special grader requirements are noted on affected tasks.
GROUP B2018 · MediumNormalized directions

Most Collinear Points

National Olympiad — Regional round (2018 season)

Submission name: lines.cpp

Problem summary

Find the largest number of distinct given points lying on one straight line.

Input

n, followed by n integer coordinate pairs.

Output

The maximum collinear count.

Constraints

2 ≤ n ≤ 999; −99 ≤ x,y ≤ 99; all points are distinct.

Worked example

An independently prepared example for this explanation.

Input

6
0 0
2 1
-2 -1
-2 -2
6 3
-2 3

Output

4

Solution analysis

  1. Fix one input point as an anchor. Every other point defines an integer direction (dx,dy). Divide both components by gcd(|dx|,|dy|) to obtain a primitive direction.
  2. A line extends both ways, so normalize the sign: dx must be positive, or when dx=0, dy must be positive. Sort normalized directions; each run of equal directions is one line through the anchor. Add one for the anchor itself.
  3. In the example, (0,0), (2,1), (−2,−1) and (6,3) all reduce to direction (2,1) when anchored at the origin. The run has three other points, giving four in total.

Why it works

Two nonzero integer displacement vectors have the same normalized primitive direction exactly when they are parallel, allowing opposite signs. Therefore each sorted run consists precisely of the other points on one line through the anchor. Every optimal line contains an input anchor, so maximizing over anchors finds its complete size.

Complexity: O(n² log n) time; O(n) additional space.

Watch out. Normalize opposite directions together. Avoid floating-point slopes, including special vertical-line cases. Distinctness ensures the gcd is never zero.

Commented C++17 solution

An independently written complete program with standard headers.

#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<numeric>
#include<utility>
#include<vector>
// Algorithm: Fix one input point as an anchor.
using namespace std;
int main(){
    int n;
    cin>>n;
    vector<pair<int,int>>points(n);
    for(auto&point:points){
        cin>>point.first>>point.second;
    }
    int answer=1;
    for(int i=0;i<n;i++){
        vector<pair<int,int>>direction;
        for(int j=0;j<n;j++){
            if(i==j){
                continue;
            }
            int dx=points[j].first-points[i].first;
            int dy=points[j].second-points[i].second;
            int divisor=gcd(abs(dx),abs(dy));
            dx/=divisor;
            dy/=divisor;
            if(dx<0||(dx==0&&dy<0)){
                dx=-dx;
                dy=-dy;
            }
            direction.emplace_back(dx,dy);
        }
        sort(direction.begin(),direction.end());
        int run=0;
        for(int j=0;j<static_cast<int>(direction.size());j++){
            run=j>0&&direction[j]==direction[j-1]?run+1:1;
            answer=max(answer,run+1);
        }
    }
    cout<<answer<<'\n';
}

Source: Arena Olimpiici ↗