Find minimum y coordinates from set of N lines in a plane

Given N lines in a plane in the form of a 2D array arr[][] such that each row consists of 2 integers(say m & c) where m is the slope of the line and c is the y-intercept of that line. You are given Q queries each consist of x-ordinates. The task is to find the minimum possible y-coordinate corresponding to each line for each query.

Examples:

Input: arr[][] = { { 4, 0 }, { -3, 0 }, { 5, 1 }, { 3, -1 },{ 2, 3 }, { 1, 4 } } and Q[] = {-6, 3, 100}
Output:
-29
-9
-300
Explanation:
The minimum value for x = -6 from the given set of lines is -29.
The minimum value for x = 3 from the given set of lines is -9.
The minimum value for x = -100 from the given set of lines is -300.



Naive Approach: The naive approach is to find the y-coordinates for each line and the minimum of all the y-coordinates will give the minimum y-coordinate value. Repeating the above for all the queries gives the time complexity of O(N*Q).

Efficient Approach:

Observations

  1. L1 an L2 are two lines and they intersect at (x1, y1), if L1 is lower than before x = x1 then L2 will be lower than L1 after x = x1. This implies that the lines gives lower value for some continous ranges.
  2. L4 is the line which is parallel to x axis, which is constant as y = c4 and never gives minimum correspoding to all the lines.
  3. Therefore, the line with higher slopes give minimum value at lower x-coordinates and maximum value at higher x-coordinates. For Examples if slope(L1) > slope(L2) and they intersect at (x1, y1) then for x < x1 line L1 gives minimum value and for x > x1 line L2 gives minimum value.
  4. For lines L1, L2 and L3, if slope(L1) > slope(L2) > slope(L3) and if intersection point of L1 and L3 is below than L1 and L2, then we can neglact the line L2 as it cannot gives minimum value for any x-coordinates.

On the basis of the above observations following are the steps:

  1. Sort the slopes in decreasing order of slope.
  2. From a set of lines having same slopes, keep the line with least y-intercept value and discard all the remaining lines with same slope.
  3. Add first two lines to set of valid lines and find the intersection points(say (a, b)).
  4. For the next set of remaining lines do the following:
    • Find the intersection point(say (c, d)) of the second last line and the current line.
    • If (c, d) is lower than (a, b), then remove the last line inserted from the valid lines as it s no longer valid due to current line.
  5. Repeat the above steps to generate all the valid lines set.
  6. Now we have valid lines set and each line in the valid lines set forms the minimum in a continous range in increasing order i.e., L1 is minimum in range [a, b] and L2 in range [b, c].
  7. Perform Binary Search on ranges[] to find the minimum y-coordinates for each queries of x-cordinates.

Below is the implementation of the above approach:

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program for the above approach
#include <bits/stdc++.h>
using namespace std;
  
// To store the valid lines
vector<pair<int, int> > lines;
  
// To store the distinct lines
vector<pair<int, int> > distinct;
  
// To store the ranges of intersection
// points
vector<pair<int, int> > ranges;
  
// Function that returns the intersection
// points
pair<int, int> intersection(pair<int, int> a,
                            pair<int, int> b)
{
    int x = a.second - b.second;
    int y = b.first - a.first;
    return { x, y };
}
  
// Function to see if a line is eligible
// or not.
// L3 is the current line being added and
// we check eligibility of L2
bool isleft(pair<int, int> l1,
            pair<int, int> l2,
            pair<int, int> l3)
{
    pair<int, int> x1, x2;
  
    // Find intersections
    x1 = intersection(l1, l3);
    x2 = intersection(l1, l2);
  
    // Returns true if x1 is left of x2
    return (x1.first * x2.second
            < x2.first * x1.second);
}
  
// Comparator function to sort the line[]
bool cmp(pair<int, int> a, pair<int, int> b)
{
    if (a.first != b.first)
        return a.first > b.first;
    else
        return a.second < b.second;
}
  
// Find x-coordinate of intersection
// of 2 lines
int xintersect(pair<int, int> a,
               pair<int, int> b)
{
  
    int A = a.second - b.second;
    int B = b.first - a.first;
  
    // Find the x coordinate
    int x = A / B;
  
    if (A * B < 0)
        x -= 1;
  
    return x;
}
  
// Function to returns the minimum
// possible value for y
int findy(vector<pair<int, int> >& ranges,
          int pt)
{
    int lo = 0, hi = ranges.size() - 1;
    int mid = 0;
  
    // Binary search to find the minimum
    // value
    while (lo <= hi) {
  
        // Find middle element
        mid = (lo + hi) / 2;
  
        if (ranges[mid].first <= pt
            && ranges[mid].second >= pt) {
            break;
        }
        else if (ranges[mid].first > pt) {
            hi = mid - 1;
        }
        else {
            lo = mid + 1;
        }
    }
  
    // Returns the minimum value
    return lines[mid].first * pt + lines[mid].second;
}
  
// Function to add a valid line and
// remove the invalid lines
void add(pair<int, int> x)
{
    // Add the current line
    lines.push_back(x);
  
    // While Loop
    while (lines.size() >= 3
           && isleft(lines[lines.size() - 3],
                     lines[lines.size() - 2],
                     lines[lines.size() - 1])) {
  
        // Erase invalid lines
        lines.erase(lines.end() - 2);
    }
}
  
// Function to updateLines on the
// basis of distinct slopes
void updateLines(pair<int, int> line[],
                 int n)
{
  
    // Sort the line according to
    // decreasing order of slope
    sort(line, line + n, cmp);
  
    // To track for last slope
    int lastslope = INT_MIN;
  
    // Traverse the line[] and find
    // set of distinct lines
    for (int i = 0; i < n; i++) {
  
        if (line[i].first == lastslope)
            continue;
  
        // Push the current line in
        // array distinct[]
        distinct.push_back(line[i]);
  
        // Update the last slope
        lastslope = line[i].first;
    }
  
    // Traverse the distinct[] and
    // update the valid lines to lines[]
    for (int i = 0; i < distinct.size(); i++)
        add(distinct[i]);
  
    int left = INT_MIN;
    int i, right = 0;
  
    // Traverse the valid lines array
    for (i = 0; i < lines.size() - 1; i++) {
  
        // Find the intersection point
        int right = xintersect(lines[i],
                               lines[i + 1]);
  
        // Insert the current intersection
        // points in ranges[]
        ranges.push_back({ left, right });
  
        left = right + 1;
    }
  
    ranges.push_back({ left, INT_MAX });
}
  
// Driver Code
int main()
{
    int n = 6;
  
    // Set of lines of slopes and y intercept
    pair<int, int> line[] = { { 4, 0 }, { -3, 0 }, 
                              { 5, 1 }, { 3, -1 }, 
                              { 2, 3 }, { 1, 4 } };
  
    // Function Call
    updateLines(line, n);
  
    // Queries for x-coordinates
    int Q[] = { -6, 3, 100 };
  
    // Traverse Queries to find minimum
    // y-coordinates
    for (int i = 0; i < 3; i++) {
  
        // Use Binary Search in ranges
        // to find the minimum y-coordinates
        cout << findy(ranges, Q[i])
             << endl;
    }
    return 0;
}

chevron_right


Output:

-29
-9
-300

Time Complexity: O(N + Q*log N), where N is the number of lines and Q is the numbers of queries.

GeeksforGeeks has prepared a complete interview preparation course with premium videos, theory, practice problems, TA support and many more features. Please refer Placement 100 for details




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.