📜  从平面中的N条线中找到最小的y坐标

📅  最后修改于: 2021-04-17 13:50:36             🧑  作者: Mango

在平面中以二维数组arr [] []的形式给出N条线,使得每行包含2个整数(例如m&c ),其中m是线的斜率, c是该线的y截距。您会得到Q个查询,每个查询都由x坐标组成。任务是为每个查询找到与每一行相对应的最小y坐标。

例子:

天真的方法:天真的方法是找到每条线的y坐标,所有y坐标中的最小值将给出最小的y坐标值。对所有查询重复以上操作,将得出O(N * Q)的时间复杂度。

高效方法:

观察结果

  1. L1L2是两行,它们相交于(X1,Y1),如果L1比前X = X1下然后L2将在x = X1L1更低。这意味着对于某些连续范围,这些线给出的值较低。
  2. L4是平行于x轴的线,其常数为y = c4,并且从不对所有线给出最小的对应关系。
  3. 因此,具有较高斜率的线在较低的x坐标处给出最小值,而在较高的x坐标处给出最大值。对于示例,如果斜率(L1) >斜率(L2)且它们在(x1,y1)相交,则对于x 线L1给出最小值,而对于x> x1线L2给出最小值。
  4. 对于线L1,L2和L3,如果斜率(L1)>斜率(L2)>斜率(L3),并且如果L1和L3的交点低于L1和L2 ,则可以对线L2进行遮蔽,因为它不能给出最小值任何x坐标的值。

根据上述观察结果,请执行以下步骤:

  1. 按斜率的降序对斜率进行排序。
  2. 从具有相同斜率的一组线中,使该线的y截距值最小,并丢弃所有其余的具有相同斜率的线。
  3. 将前两行添加到一组有效线中,并找到相交点(例如(a,b) )。
  4. 对于下一组剩余的行,请执行以下操作:
    • 找到倒数第二条线和当前线的交点(例如(c,d))。
    • 如果(c,d)小于(a,b) ,则从有效行中删除最后插入的行,因为由于当前行而不再有效。
  5. 重复上述步骤以生成所有有效行集。
  6. 现在我们有了有效的行集,并且有效行集中的每一行都以递增的顺序在连续范围内形成最小值,即L1在[a,b]范围内最小,而L2在[b,c]范围内最小。
  7. 在range []上执行二进制搜索,以查找x查询的每个查询的最小y坐标

下面是上述方法的实现:

// C++ program for the above approach
#include 
using namespace std;
  
// To store the valid lines
vector > lines;
  
// To store the distinct lines
vector > distinct;
  
// To store the ranges of intersection
// points
vector > ranges;
  
// Function that returns the intersection
// points
pair intersection(pair a,
                            pair 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 l1,
            pair l2,
            pair l3)
{
    pair 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 a, pair 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 a,
               pair 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 >& 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 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 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 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;
}
输出:
-29
-9
-300

时间复杂度: O(N + Q * log N) ,其中N是行数,Q是查询数。