Minimum number of Straight Lines to connect all the given Points
Last Updated : 7 Feb, 2026
Given 2d integer array arr[][] containing N coordinates each of type {X, Y}, we have to find the minimum number of straight lines required to connect all the points of the array. Note: after drawing those lines you can travel from any point to any other point by moving along the drawn lines.
Examples:
Input: arr[][] = {{1, 7}, {2, 6}, {3, 5}, {4, 4}, {5, 4}, {6, 3}, {7, 2}, {8, 1}} Output: 3 Explanation: The diagram represents the input points and the minimum straight lines required. The following 3 lines can be drawn to represent the line chart: => Line 1 (in red) which connects (1, 7), (2, 6), (3,5) and (4,4). => Line 2 (in blue) which connects from (4, 4) to (5, 4). => Line 3 (in green) which connects (5, 4), (6, 3), (7, 2), and (8, 1).
Minimum lines to connect the points of the example
Input: arr[][] = {{3, 4}, {1, 2}, {7, 8}, {2, 3}} Output: 1 Explanation: A single line passing through all the points is enough to connect them all.
Approach
Line Precomputation: The algorithm picks every pair of points (i, j) to define a line and checks every other point (k) for collinearity using cross-multiplication. Each line is stored as a bitmask where the set bits indicate the points it covers.
Bitmask DP: A DP table of size 2^N is used to store the minimum lines for every possible subset of points. We start with 0 points covered (dp[0] = 0).
Optimal Coverage: For each state, we identify the first point not yet covered and "try" every precomputed line that could cover it. By updating the DP table with the minimum value, we ensure that we find the most efficient combination of lines.
Below is an implementation for the above approach:
C++
#include<iostream>#include<vector>#include<algorithm>#include<map>usingnamespacestd;intminimumLines(vector<vector<int>>&points){intn=points.size();if(n<=2)return(n==0)?0:1;// 1. Precompute all possible lines that can be formed// Each integer in this vector is a bitmask representing points on that linevector<int>lines;for(inti=0;i<n;i++){for(intj=i+1;j<n;j++){intmask=(1<<i)|(1<<j);longlongx1=points[i][0],y1=points[i][1];longlongx2=points[j][0],y2=points[j][1];// Check which other points 'k' lie on the line formed by 'i' and 'j'for(intk=0;k<n;k++){if(k==i||k==j)continue;longlongx3=points[k][0],y3=points[k][1];// Cross multiplication to check collinearity: (y2-y1)(x3-x2) == (y3-y2)(x2-x1)if((y2-y1)*(x3-x2)==(y3-y2)*(x2-x1)){mask|=(1<<k);}}lines.push_back(mask);}}// 2. Bitmask DP to find the minimum lines to cover all points// dp[mask] = minimum lines to cover points represented by 'mask'vector<int>dp(1<<n,n);// Initialize with max possible lines (n)dp[0]=0;for(intmask=0;mask<(1<<n);mask++){if(dp[mask]==n)continue;// Unreachable state// Find the first point not yet coveredintfirst_uncovered=0;while(first_uncovered<n&&(mask&(1<<first_uncovered))){first_uncovered++;}if(first_uncovered==n)break;// All points covered// Try covering the 'first_uncovered' point with every possible line it belongs to// Or treat it as a single point (though in this problem, any point can be a line)for(intline_mask:lines){if(line_mask&(1<<first_uncovered)){intnext_mask=mask|line_mask;dp[next_mask]=min(dp[next_mask],dp[mask]+1);}}// Case for a single point that doesn't form a line with othersintsolo_mask=mask|(1<<first_uncovered);dp[solo_mask]=min(dp[solo_mask],dp[mask]+1);}returndp[(1<<n)-1];}intmain(){vector<vector<int>>vect{{1,0},{2,0},{0,0},{4,4},{5,5}};cout<<"Minimum lines required: "<<minimumLines(vect)<<endl;// Output: 2return0;}
Java
importjava.util.*;publicclassGFG{publicstaticintminimumLines(int[][]points){intn=points.length;if(n<=2)return(n==0)?0:1;// 1. Precompute all possible lines that can be formed// Each integer in this vector is a bitmask representing points on that lineList<Integer>lines=newArrayList<>();for(inti=0;i<n;i++){for(intj=i+1;j<n;j++){intmask=(1<<i)|(1<<j);longx1=points[i][0],y1=points[i][1];longx2=points[j][0],y2=points[j][1];// Check which other points 'k' lie on the line formed by 'i' and 'j'for(intk=0;k<n;k++){if(k==i||k==j)continue;longx3=points[k][0],y3=points[k][1];// Cross multiplication to check collinearity: (y2-y1)(x3-x2) == (y3-y2)(x2-x1)if((y2-y1)*(x3-x2)==(y3-y2)*(x2-x1)){mask|=(1<<k);}}lines.add(mask);}}// 2. Bitmask DP to find the minimum lines to cover all points// dp[mask] = minimum lines to cover points represented by'mask'int[]dp=newint[1<<n];Arrays.fill(dp,n);// Initialize with max possible lines (n)dp[0]=0;for(intmask=0;mask<(1<<n);mask++){if(dp[mask]==n)continue;// Unreachable state// Find the first point not yet coveredintfirst_uncovered=0;while(first_uncovered<n&&((mask&(1<<first_uncovered))!=0)){first_uncovered++;}if(first_uncovered==n)break;// All points covered// Try covering the 'first_uncovered' point with every possible line it belongs to// Or treat it as a single point (though in this problem, any point can be a line)for(intline_mask:lines){if((line_mask&(1<<first_uncovered))!=0){intnext_mask=mask|line_mask;dp[next_mask]=Math.min(dp[next_mask],dp[mask]+1);}}// Case for a single point that doesn't form a line with othersintsolo_mask=mask|(1<<first_uncovered);dp[solo_mask]=Math.min(dp[solo_mask],dp[mask]+1);}returndp[(1<<n)-1];}publicstaticvoidmain(String[]args){int[][]vect={{1,0},{2,0},{0,0},{4,4},{5,5}};System.out.println("Minimum lines required: "+minimumLines(vect));// Output: 2}}
Python
importitertoolsdefminimumLines(points):n=len(points)ifn<=2:return(n==0)and0or1# 1. Precompute all possible lines that can be formed# Each integer in this list is a bitmask representing points on that linelines=[]fori,jinitertools.combinations(range(n),2):mask=(1<<i)|(1<<j)x1,y1=points[i]x2,y2=points[j]# Check which other points 'k' lie on the line formed by 'i' and 'j'forkinrange(n):ifk==iork==j:continuex3,y3=points[k]# Cross multiplication to check collinearity: (y2-y1)*(x3-x2) == (y3-y2)*(x2-x1)if(y2-y1)*(x3-x2)==(y3-y2)*(x2-x1):mask|=(1<<k)lines.append(mask)# 2. Bitmask DP to find the minimum lines to cover all points# dp[mask] = minimum lines to cover points represented by 'mask'dp=[n]*(1<<n)# Initialize with max possible lines (n)dp[0]=0formaskinrange(1<<n):ifdp[mask]==n:continue# Unreachable state# Find the first point not yet coveredfirst_uncovered=0whilefirst_uncovered<nand(mask&(1<<first_uncovered)):first_uncovered+=1iffirst_uncovered==n:break# All points covered# Try covering the 'first_uncovered' point with every possible line it belongs to# Or treat it as a single point (though in this problem, any point can be a line)forline_maskinlines:ifline_mask&(1<<first_uncovered):next_mask=mask|line_maskdp[next_mask]=min(dp[next_mask],dp[mask]+1)# Case for a single point that doesn't form a line with otherssolo_mask=mask|(1<<first_uncovered)dp[solo_mask]=min(dp[solo_mask],dp[mask]+1)returndp[(1<<n)-1]# Example usagevect=[[1,0],[2,0],[0,0],[4,4],[5,5]]print("Minimum lines required:",minimumLines(vect))# Output: 2
C#
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;publicclassGFG{publicstaticvoidMain(){varvect=newList<Tuple<int,int>>{newTuple<int,int>(1,0),newTuple<int,int>(2,0),newTuple<int,int>(0,0),newTuple<int,int>(4,4),newTuple<int,int>(5,5)};Console.WriteLine("Minimum lines required: "+minimumLines(vect));}staticintminimumLines(List<Tuple<int,int>>points){intn=points.Count;if(n<=2)return(n==0)?0:1;// 1. Precompute all possible lines that can be formed// Each integer in this list is a bitmask representing points on that lineList<int>lines=newList<int>();for(inti=0;i<n;i++){for(intj=i+1;j<n;j++){intmask=(1<<i)|(1<<j);varp1=points[i];varp2=points[j];// Check which other points 'k' lie on the line formed by 'i' and 'j'for(intk=0;k<n;k++){if(k==i||k==j)continue;varp3=points[k];// Cross multiplication to check collinearity: (y2-y1)*(x3-x2) == (y3-y2)*(x2-x1)if((p2.Item2-p1.Item2)*(p3.Item1-p2.Item1)==(p3.Item2-p2.Item2)*(p2.Item1-p1.Item1)){mask|=(1<<k);}}lines.Add(mask);}}// 2. Bitmask DP to find the minimum lines to cover all pointsint[]dp=Enumerable.Repeat(n,1<<n).ToArray();// Initialize with max possible lines (n)dp[0]=0;for(intmask=0;mask<(1<<n);mask++){if(dp[mask]==n)continue;// Unreachable state// Find the first point not yet coveredintfirst_uncovered=0;while(first_uncovered<n&&(mask&(1<<first_uncovered))!=0){first_uncovered++;}if(first_uncovered==n)break;// All points covered// Try covering the 'first_uncovered' point with every possible line it belongs to// Or treat it as a single point (though in this problem, any point can be a line)foreach(varline_maskinlines){if((line_mask&(1<<first_uncovered))!=0){intnext_mask=mask|line_mask;dp[next_mask]=Math.Min(dp[next_mask],dp[mask]+1);}}// Case for a single point that doesn't form a line with othersintsolo_mask=mask|(1<<first_uncovered);dp[solo_mask]=Math.Min(dp[solo_mask],dp[mask]+1);}returndp[(1<<n)-1];}}
JavaScript
constreadline=require('readline');constrl=readline.createInterface({input:process.stdin,output:process.stdout});functionTuple(item1,item2){this.Item1=item1;this.Item2=item2;}functionminimumLines(points){constn=points.length;if(n<=2)return(n===0)?0:1;// 1. Precompute all possible lines that can be formed// Each integer in this list is a bitmask representing points on that lineletlines=[];for(leti=0;i<n;i++){for(letj=i+1;j<n;j++){letmask=(1<<i)|(1<<j);letp1=points[i];letp2=points[j];// Check which other points 'k' lie on the line formed by 'i' and 'j'for(letk=0;k<n;k++){if(k===i||k===j)continue;letp3=points[k];// Cross multiplication to check collinearity: (y2-y1)*(x3-x2) == (y3-y2)*(x2-x1)if((p2.Item2-p1.Item2)*(p3.Item1-p2.Item1)===(p3.Item2-p2.Item2)*(p2.Item1-p1.Item1)){mask|=(1<<k);}}lines.push(mask);}}// 2. Bitmask DP to find the minimum lines to cover all pointsletdp=Array(1<<n).fill(n);// Initialize with max possible lines (n)dp[0]=0;for(letmask=0;mask<(1<<n);mask++){if(dp[mask]===n)continue;// Unreachable state// Find the first point not yet coveredletfirst_uncovered=0;while(first_uncovered<n&&(mask&(1<<first_uncovered))!==0){first_uncovered++;}if(first_uncovered===n)break;// All points covered// Try covering the 'first_uncovered' point with every possible line it belongs to// Or treat it as a single point (though in this problem, any point can be a line)for(letline_maskoflines){if((line_mask&(1<<first_uncovered))!==0){letnext_mask=mask|line_mask;dp[next_mask]=Math.min(dp[next_mask],dp[mask]+1);}}// Case for a single point that doesn't form a line with othersletsolo_mask=mask|(1<<first_uncovered);dp[solo_mask]=Math.min(dp[solo_mask],dp[mask]+1);}returndp[(1<<n)-1];}letvect=[newTuple(1,0),newTuple(2,0),newTuple(0,0),newTuple(4,4),newTuple(5,5)];console.log("Minimum lines required: "+minimumLines(vect));
Output
Minimum lines required: 2
Time complexity: O(2^N x N^2) Auxiliary Space: O(2^N)