Given three non-collinear points p, q, and r with integer coordinates in the X-Y plane, find the number of integral (lattice) points that lie strictly inside the triangle formed by these three points.Â
A point is called an integral/lattice point if both its x-coordinate and y-coordinate are integers.Â
Points lying on the boundary of the triangle are not counted.
[Naive Approach] Checking Points in Bounding Rectangle - O(W Ă— H) Time and O(1) Space
The idea is to check every integral point inside the bounding rectangle of the triangle and find if it lies strictly inside the triangle using cross products.
Working of Approach:
Find the minimum and maximum x and y coordinates among the three vertices.
Traverse all integral points (x, y) inside this bounding rectangle.
For each point, calculate its cross product with all three edges of the triangle.
If all cross products have the same sign and none is zero, the point lies strictly inside the triangle.
Count all such points and return the total.
C++
#include<iostream>#include<vector>#include<algorithm>#include<cstdlib>usingnamespacestd;// Calculate cross product of AB and AP.longlongcross(vector<int>&a,vector<int>&b,longlongx,longlongy){return1LL*(b[0]-a[0])*(y-a[1])-1LL*(b[1]-a[1])*(x-a[0]);}// Check if the point lies strictly inside the triangle.boolisInside(vector<int>&p,vector<int>&q,vector<int>&r,longlongx,longlongy){longlongc1=cross(p,q,x,y);longlongc2=cross(q,r,x,y);longlongc3=cross(r,p,x,y);// Points on the boundary are not counted.if(c1==0||c2==0||c3==0)returnfalse;// All cross products must have the same sign.return(c1>0&&c2>0&&c3>0)||(c1<0&&c2<0&&c3<0);}intinternalCount(vector<int>&p,vector<int>&q,vector<int>&r){intminX=min({p[0],q[0],r[0]});intmaxX=max({p[0],q[0],r[0]});intminY=min({p[1],q[1],r[1]});intmaxY=max({p[1],q[1],r[1]});intres=0;// Check every integral point in the bounding rectangle.for(longlongx=minX;x<=maxX;x++){for(longlongy=minY;y<=maxY;y++){if(isInside(p,q,r,x,y))res++;}}returnres;}intmain(){vector<int>p={0,0};vector<int>q={0,5};vector<int>r={5,0};cout<<internalCount(p,q,r);return0;}
Java
importjava.util.*;classGFG{// Calculate cross product of AB and AP.longcross(int[]a,int[]b,longx,longy){return1L*(b[0]-a[0])*(y-a[1])-1L*(b[1]-a[1])*(x-a[0]);}// Check if the point lies strictly inside the triangle.booleanisInside(int[]p,int[]q,int[]r,longx,longy){longc1=cross(p,q,x,y);longc2=cross(q,r,x,y);longc3=cross(r,p,x,y);// Points on the boundary are not counted.if(c1==0||c2==0||c3==0)returnfalse;// All cross products must have the same sign.return(c1>0&&c2>0&&c3>0)||(c1<0&&c2<0&&c3<0);}intinternalCount(int[]p,int[]q,int[]r){intminX=Math.min(p[0],Math.min(q[0],r[0]));intmaxX=Math.max(p[0],Math.max(q[0],r[0]));intminY=Math.min(p[1],Math.min(q[1],r[1]));intmaxY=Math.max(p[1],Math.max(q[1],r[1]));intres=0;// Check every integral point in the bounding// rectangle.for(longx=minX;x<=maxX;x++){for(longy=minY;y<=maxY;y++){if(isInside(p,q,r,x,y))res++;}}returnres;}publicstaticvoidmain(String[]args){GFGobj=newGFG();int[]p={0,0};int[]q={0,5};int[]r={5,0};System.out.println(obj.internalCount(p,q,r));}}
Python
defcross(a,b,x,y):# Calculate cross product of AB and AP.return(b[0]-a[0])*(y-a[1])-(b[1]-a[1])*(x-a[0])defisInside(p,q,r,x,y):c1=cross(p,q,x,y)c2=cross(q,r,x,y)c3=cross(r,p,x,y)# Points on the boundary are not counted.ifc1==0orc2==0orc3==0:returnFalse# All cross products must have the same sign.return(c1>0andc2>0andc3>0)or(c1<0andc2<0andc3<0)definternalCount(p,q,r):minX=min(p[0],q[0],r[0])maxX=max(p[0],q[0],r[0])minY=min(p[1],q[1],r[1])maxY=max(p[1],q[1],r[1])res=0# Check every integral point in the bounding rectangle.forxinrange(minX,maxX+1):foryinrange(minY,maxY+1):ifisInside(p,q,r,x,y):res+=1returnresif__name__=="__main__":p=[0,0]q=[0,5]r=[5,0]print(internalCount(p,q,r))
C#
usingSystem;classGFG{// Calculate cross product of AB and AP.longCross(int[]a,int[]b,longx,longy){return1L*(b[0]-a[0])*(y-a[1])-1L*(b[1]-a[1])*(x-a[0]);}// Check if the point lies strictly inside the triangle.boolIsInside(int[]p,int[]q,int[]r,longx,longy){longc1=Cross(p,q,x,y);longc2=Cross(q,r,x,y);longc3=Cross(r,p,x,y);// Points on the boundary are not counted.if(c1==0||c2==0||c3==0)returnfalse;// All cross products must have the same sign.return(c1>0&&c2>0&&c3>0)||(c1<0&&c2<0&&c3<0);}publicintinternalCount(int[]p,int[]q,int[]r){intminX=Math.Min(p[0],Math.Min(q[0],r[0]));intmaxX=Math.Max(p[0],Math.Max(q[0],r[0]));intminY=Math.Min(p[1],Math.Min(q[1],r[1]));intmaxY=Math.Max(p[1],Math.Max(q[1],r[1]));intres=0;// Check every integral point in the bounding// rectangle.for(longx=minX;x<=maxX;x++){for(longy=minY;y<=maxY;y++){if(IsInside(p,q,r,x,y))res++;}}returnres;}publicstaticvoidMain(){GFGobj=newGFG();int[]p={0,0};int[]q={0,5};int[]r={5,0};Console.WriteLine(obj.internalCount(p,q,r));}}
JavaScript
functioncross(a,b,x,y){// Calculate cross product of AB and AP.return((b[0]-a[0])*(y-a[1])-(b[1]-a[1])*(x-a[0]));}functionisInside(p,q,r,x,y){letc1=cross(p,q,x,y);letc2=cross(q,r,x,y);letc3=cross(r,p,x,y);// Points on the boundary are not counted.if(c1===0||c2===0||c3===0)returnfalse;// All cross products must have the same sign.return(c1>0&&c2>0&&c3>0)||(c1<0&&c2<0&&c3<0);}functioninternalCount(p,q,r){letminX=Math.min(p[0],q[0],r[0]);letmaxX=Math.max(p[0],q[0],r[0]);letminY=Math.min(p[1],q[1],r[1]);letmaxY=Math.max(p[1],q[1],r[1]);letres=0;// Check every integral point in the bounding rectangle.for(letx=minX;x<=maxX;x++){for(lety=minY;y<=maxY;y++){if(isInside(p,q,r,x,y))res++;}}returnres;}// Driver Codeletp=[0,0];letq=[0,5];letr=[5,0];console.log(internalCount(p,q,r));
Output
6
[Expected Approach] Using Pick's Theorem - O(log C) Time and O(1) Space
The idea is to use Pick's Theorem, which relates the area of a lattice triangle with its interior and boundary lattice points.
Pick's Theorem, states that the following equation holds true for a simple polygon.
A = I + (B / 2) - 1
A ==> Area of Polygon
B ==> Number of integral points on edges of polygon
I ==> Number of integral points inside the polygon
Using the above formula, we can deduce:
I = (2A - B + 2) / 2
We can find A (area of the triangle) using the Shoelace Formula.
How to Find B (Number of Integral Points on Edges of a Triangle)?
We can find the number of integral points between any two vertices V1 and V2 of the triangle using the following:
If the edge joining V1 and V2 is parallel to the X-axis, the number of integral points between the vertices is abs(V1.x - V2.x) - 1.
If the edge is parallel to the Y-axis, the number of integral points between the vertices is abs(V1.y - V2.y) - 1.
Otherwise, the number of integral points between the vertices can be found using GCD(abs(V1.x - V2.x), abs(V1.y - V2.y)) - 1.
The above GCD formula also works for horizontal and vertical edges, so it can be used directly in the implementation.
We calculate this value for all three edges and add the three vertices to obtain the total number of boundary points.
The formula for finding the integral points between two vertices can be derived using simple geometry. One way to understand it is to shift the edge such that one of its vertices lies at the origin.
Let us understand with an example: Input: p[] = [0, 0], q[] = [0,5], r[] = [5,0]
For edges (p, q), (q, r) and (r, p), the number of integral points between the vertices is 4, 4 and 4, respectively. Adding the 3 vertices gives boundary = 15.
Using the Shoelace formula, doubleArea = |0 + 25 + 0| = 25.
Hence, the number of integral points strictly inside the triangle is 6.
C++
#include<iostream>#include<vector>#include<algorithm>#include<cstdlib>usingnamespacestd;intgcd(inta,intb){while(b!=0){inttemp=a%b;a=b;b=temp;}returna;}intgetBoundaryCount(vector<int>&p,vector<int>&q){returngcd(abs(p[0]-q[0]),abs(p[1]-q[1]))-1;}intinternalCount(vector<int>&p,vector<int>&q,vector<int>&r){// Count all lattice points on the boundary.intboundary=getBoundaryCount(p,q)+getBoundaryCount(q,r)+getBoundaryCount(r,p)+3;// Calculate twice the area of the triangle.intdoubleArea=abs(p[0]*(q[1]-r[1])+q[0]*(r[1]-p[1])+r[0]*(p[1]-q[1]));// Apply Pick's theorem to find interior lattice points.return(doubleArea-boundary+2)/2;}intmain(){vector<int>p={0,0};vector<int>q={0,5};vector<int>r={5,0};cout<<internalCount(p,q,r);return0;}
Java
importjava.util.*;classGFG{intgcd(inta,intb){while(b!=0){inttemp=a%b;a=b;b=temp;}returna;}intgetBoundaryCount(int[]p,int[]q){returngcd(Math.abs(p[0]-q[0]),Math.abs(p[1]-q[1]))-1;}intinternalCount(int[]p,int[]q,int[]r){// Count all lattice points on the boundary.intboundary=getBoundaryCount(p,q)+getBoundaryCount(q,r)+getBoundaryCount(r,p)+3;// Calculate twice the area of the triangle.intdoubleArea=Math.abs(p[0]*(q[1]-r[1])+q[0]*(r[1]-p[1])+r[0]*(p[1]-q[1]));// Apply Pick's theorem to find interior lattice// points.return(doubleArea-boundary+2)/2;}publicstaticvoidmain(String[]args){GFGobj=newGFG();int[]p={0,0};int[]q={0,5};int[]r={5,0};System.out.println(obj.internalCount(p,q,r));}}
Python
frommathimportgcdfromtypingimportListdefgcd(a:int,b:int)->int:whileb!=0:temp=a%ba=bb=tempreturnadefgetBoundaryCount(p:List[int],q:List[int])->int:returngcd(abs(p[0]-q[0]),abs(p[1]-q[1]))-1definternalCount(p:List[int],q:List[int],r:List[int])->int:# Count all lattice points on the boundary.boundary=getBoundaryCount(p,q)+getBoundaryCount(q,r)+getBoundaryCount(r,p)+3# Calculate twice the area of the triangle.doubleArea=abs(p[0]*(q[1]-r[1])+q[0]*(r[1]-p[1])+r[0]*(p[1]-q[1]))# Apply Pick's theorem to find interior lattice points.return(doubleArea-boundary+2)//2if__name__=="__main__":p=[0,0]q=[0,5]r=[5,0]print(internalCount(p,q,r))
C#
usingSystem;classGFG{intGcd(inta,intb){while(b!=0){inttemp=a%b;a=b;b=temp;}returna;}intgetBoundaryCount(int[]p,int[]q){returnGcd(Math.Abs(p[0]-q[0]),Math.Abs(p[1]-q[1]))-1;}publicintinternalCount(int[]p,int[]q,int[]r){// Count all lattice points on the boundary.intboundary=getBoundaryCount(p,q)+getBoundaryCount(q,r)+getBoundaryCount(r,p)+3;// Calculate twice the area of the triangle.intdoubleArea=Math.Abs(p[0]*(q[1]-r[1])+q[0]*(r[1]-p[1])+r[0]*(p[1]-q[1]));// Apply Pick's theorem to find interior lattice// points.return(doubleArea-boundary+2)/2;}publicstaticvoidMain(){GFGobj=newGFG();int[]p={0,0};int[]q={0,5};int[]r={5,0};Console.WriteLine(obj.internalCount(p,q,r));}}
JavaScript
functiongcd(a,b){while(b!=0){lettemp=a%b;a=b;b=temp;}returna;}functiongetBoundaryCount(p,q){returngcd(Math.abs(p[0]-q[0]),Math.abs(p[1]-q[1]))-1;}functioninternalCount(p,q,r){// Count all lattice points on the boundary.letboundary=getBoundaryCount(p,q)+getBoundaryCount(q,r)+getBoundaryCount(r,p)+3;// Calculate twice the area of the triangle.letdoubleArea=Math.abs(p[0]*(q[1]-r[1])+q[0]*(r[1]-p[1])+r[0]*(p[1]-q[1]));// Apply Pick's theorem to find interior lattice points.returnMath.floor((doubleArea-boundary+2)/2);}// Driver Codeletp=[0,0];letq=[0,5];letr=[5,0];console.log(internalCount(p,q,r));