📜  从平面中的一组 N 条线中查找最小 y 坐标

📅  最后修改于: 2021-09-16 11:11:39             🧑  作者: Mango

给定平面中二维数组arr[][]形式的 N条线,每行由 2 个整数组成(比如m & c ),其中m是线的斜率, c是该线的 y 截距.给你Q 个查询,每个查询由x-coordinates 组成。任务是为每个查询找到对应于每一行的最小可能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 < x1,线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-coordinates的每个查询的最小 y 坐标

下面是上述方法的实现:

CPP
// 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 是查询数。

如果您希望与专家一起参加现场课程,请参阅DSA 现场工作专业课程学生竞争性编程现场课程。