计算一组重叠线段覆盖的总面积的算法?

发布于 2024-12-03 21:20:21 字数 283 浏览 0 评论 0原文

我有一个可能重叠间隔的端点列表,并且我想要一种有效的方法来计算 k 间隔覆盖的总面积,对于 k=1,2,... (无需执行所有操作)两两比较)。或者说,这不可能吗?

例如,假设 x 是起点列表,y 是终点列表, 并且 x[i] y[i],这样

x = (1.5, 2, 3, 5)
y = (3, 4, 4, 6)

至少一个区间覆盖的总面积为 3.5,至少两个区间覆盖的总面积为 1。

谢谢,ph。

I have a list of endpoints of possibly overlapping intervals, and I'd like an efficient way to compute the total area covered by k intervals, for k=1,2,... (without doing all pairwise comparisons). Or, is this not possible?

For example, suppose x is the list of start points, and y is the list of end points,
and that x[i] < y[i], and

x = (1.5, 2, 3, 5)
y = (3, 4, 4, 6)

so that the total area covered by at least one interval is 3.5, and the total area covered by at least two is 1.

thanks, ph.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

近箐 2024-12-10 21:20:21

这是计算几何中的经典线扫描问题。

在每个起点处放置 +1,在每个终点处放置 -1。然后想象一下沿着数轴从负无穷到正无穷行走。

每次遇到+1时,你的身高就增加1。每次遇到-1时,你的身高就会减少。当您在数轴上从 p1 移动到 p2 时,将 p2 - p1(扫描长度)添加到给定高度所覆盖的量。

然后您将得到每个高度精确覆盖的长度直方图。如果您想处理“至少两个间隔”的情况,您可以累积总数。

This is a classic line sweep problem from computational geometry.

Put a +1 at each start point, and a -1 at every end point. Then imagine walking on the number line from negative infinity to positive infinity.

Every time you encounter a +1, increment your height by 1. Everytime you hit a -1, decrease your height. As you move from p1 to p2 on the number line, add p2 - p1 (length swept) to the amount covered by the given height.

Then you'll have a histogram of lengths covered by exactly by each height. You can accumulate the totals if you want to handle the "at least two intervals" case.

甜柠檬 2024-12-10 21:20:21

我不知道 @rrenaud 在我写同样的东西时发布了他的解决方案,所以我将省略解释,只给你代码。这是线扫描的 javascript 版本:

// x and y inputs are your start and end points for ranges,
// as in the example data
function countOverlapRanges(x, y) {
    var ranges = [];
    var n = x.length;
    if (n !== y.length) {
        throw "Input arrays must be the same length!";
    }
    var i;

    // iterate over all inputs, pushing them into the array
    for (i = 0; i < n; ++i) {
        ranges.push({
            value: x[i],
            change: 1
        });
        ranges.push({
            value: y[i],
            change: -1
        });
    }

    // sort the array into number-line order
    ranges.sort(function (a, b) {
        return a.value - b.value;
    });

    var result = {};
    var k = 1;
    var maxK = 1;
    n = ranges.length;

    // iterate over the sorted data, counting the size of ranges
    var cur, value, lastValue = ranges[0].value;
    for (i = 1; i < n; ++i) {
        cur = ranges[i];
        value = cur.value;
        if (k) {
            var difference = value - lastValue;
            result[k] = (result[k] || 0) + difference;
        }
        k += cur.change;
        maxK = Math.max(maxK, k);
        lastValue = value;
    }

    // so far we've counted the ranges covered by exactly k intervals.
    // adjust the results to get the size of ranges covered by
    // at least k intervals.
    var sum = 0;
    for (i = maxK; i > 0; --i) {
        sum = result[i] = sum + result[i];
    }

    return result;
}

它返回一个将 k 值映射到沿线距离的对象。

I didn't know @rrenaud had posted his solution while I was writing the same thing, so I'll omit the explanation and just give you the code. This is a javascript version of line sweep:

// x and y inputs are your start and end points for ranges,
// as in the example data
function countOverlapRanges(x, y) {
    var ranges = [];
    var n = x.length;
    if (n !== y.length) {
        throw "Input arrays must be the same length!";
    }
    var i;

    // iterate over all inputs, pushing them into the array
    for (i = 0; i < n; ++i) {
        ranges.push({
            value: x[i],
            change: 1
        });
        ranges.push({
            value: y[i],
            change: -1
        });
    }

    // sort the array into number-line order
    ranges.sort(function (a, b) {
        return a.value - b.value;
    });

    var result = {};
    var k = 1;
    var maxK = 1;
    n = ranges.length;

    // iterate over the sorted data, counting the size of ranges
    var cur, value, lastValue = ranges[0].value;
    for (i = 1; i < n; ++i) {
        cur = ranges[i];
        value = cur.value;
        if (k) {
            var difference = value - lastValue;
            result[k] = (result[k] || 0) + difference;
        }
        k += cur.change;
        maxK = Math.max(maxK, k);
        lastValue = value;
    }

    // so far we've counted the ranges covered by exactly k intervals.
    // adjust the results to get the size of ranges covered by
    // at least k intervals.
    var sum = 0;
    for (i = maxK; i > 0; --i) {
        sum = result[i] = sum + result[i];
    }

    return result;
}

It returns an object that maps k values to distances along the line.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文