【问题标题】:How to cheaply deal with multiple ranges (finding a maximum)如何廉价地处理多个范围(找到最大值)
【发布时间】:2017-11-28 11:14:10
【问题描述】:

我有很多范围,每个范围都有一个重量。总范围上的每个点都由该点所在的所有范围的权重之和评分。我希望能够廉价地找到积分的总价值,并希望能够找到最大值。理想情况下,它还能够找到一组(等距)间隔点的最大值。

不幸的是,我受到性能的严重限制,并且正在努力为此找到一个好的算法。

我能找到的仅有的两个不错的解决方案是: - 通过对一堆点进行采样来暴力破解它。对于每个:检查每个范围是否适合,找到总值,然后检查它是否比目前最好的更好。通过取范围的边界可以找到体面点样本。 - 创建一组桶。遍历所有范围,将值添加到适合范围内的所有存储桶。然后遍历所有的桶以找到最好的一个

两者都不是我喜欢的速度(它们已经过测试),而且后者不是连续的,因此存在准确性问题。

只要性能更好,我会接受稍微不准确的响应。 给我的特殊情况增加一点额外复杂性的是,我实际上是在处理角度,所以环境是模块化的。无法订购范围,我需要确保从 340 度到 20 度的范围包含 350 度和 10 度的点。 我正在处理的角度范围不能超过 180 度,而且很少超过 90 度。 范围的数量通常不是很高(1-30),但我需要做很多计算。

如果重要的话,语言是 Java。

【问题讨论】:

  • 您能否更准确地描述问题?
  • 你能举个例子代替冗长的解释吗?
  • 我需要找到一个最佳的发射角度。我的游戏世界中有一些物体,我的位置在角度方向上的假想线需要与之相交,因为我想击中或阻止击中它们。有些物品比其他物品更有价值(因此有重量)。每个对象都可以表示为相交的最右角和最右角,这些是范围。在某些情况下,我需要有一组线与尽可能多的线相交,想象一下霰弹枪式的射击,几颗子弹以不同的、可预测的角度飞走。

标签: java algorithm performance range maximize


【解决方案1】:

制作角度区间的列表(数组)。如果区间结束值小于起始值 (20

制作一对列表(角度,起点+权重或终点-权重)。

将列表与其副本连接起来以提供圆形交集。 (可以只复制列表的一部分)

按角度对它们进行排序(在平局的情况下使用 +/- 作为辅助键:- 在 + 之前)

使 CurrWeight=0

遍历列表,将 +/weight 字段添加到 CurrWeight。检查最大值。

(这种方法适用于线性列表,我尝试将其修改为循环列表,也许我可能会错过一些警告)

【讨论】:

  • 这似乎可行!谢谢!至少就 O 表示法而言,这应该更低。我将不得不尝试一下,因为在实践中,这种排序可能最终与其他方法一样昂贵。只需复制跨越 0 角的范围并在 0 以下开始我的值跟踪可能会起作用(尽管在超过 0 之前无法获得结果)。
  • 排序是 O(nlogn)。确实需要将列表的一部分复制到最后完成时间(例如,最后一次 360+70 限制为 70)
  • 恕我直言,这种重复只会让事情变得更复杂。那这个呢? 1. 通过迭代原始范围一次来确定 0 度的值。 2. 将所有角度视为区间(0, 360) 中的数字。 3. 为每个开始添加(x, +weight),为每个结束添加(x, -weight),并像往常一样对该列表进行排序。忽略循环。
【解决方案2】:

在这里,我应该更好地使用术语“边界”而不是“边缘”,因为它指的是区间边界

    import java.util.ArrayList;
import java.util.Iterator;
import java.util.SortedSet;
import java.util.TreeSet;

public class Main {

    ArrayList<Interval> intervals;

    public static void main(String args[]) {

        Main main = new Main();

        main.intervals = new ArrayList<Interval>();
        Interval i1 = new Interval(10, 30, 1);
        Interval i2= new Interval(20, 40, 1);
        Interval i3= new Interval(50, 60, 1);
        Interval i4= new Interval(0, 70, 1);

        main.intervals.add(i1);
        main.intervals.add(i2);
        main.intervals.add(i3);
        main.intervals.add(i4);

        Interval winningInterval = main.processIntervals(main.intervals);
        System.out.println("winning interval="+winningInterval);



    }


    public Interval processIntervals(ArrayList<Interval> intervals)
    {
        SortedSet<Integer> intervalEdges = new TreeSet<Integer>();

        for(int i = 0;i<intervals.size();i++)
        {
            Interval currentInterval = intervals.get(i);
            intervalEdges.add(currentInterval.a);
            intervalEdges.add(currentInterval.b);
        }

        System.out.println(intervalEdges);

        //edges stores the same data as intervalEdges, but for convenience, it is a list
        ArrayList<Integer> edges = new ArrayList<Integer>(intervalEdges);

        ArrayList<Interval> intersectionIntervals = new ArrayList<Interval>();

        for(int i=0; i<edges.size()-1;i++)
        {
            Interval newInterval = new Interval(edges.get(i), edges.get(i+1), 0);

            int score = 0; //the sum of the values of the overlapping intervals
            for(int j=0; j<intervals.size();j++)
            {
                if(newInterval.isIncludedInInterval(intervals.get(j)))
                    score = score+ intervals.get(j).val;
            }

            newInterval.val = score;
            intersectionIntervals.add(newInterval);
        }

        System.out.println(intersectionIntervals);

        int maxValue=0; //the maximum value of an interval
        Interval x = new Interval(-1,-1,0);//that interval with the maximum value
        for(int i=0; i<intersectionIntervals.size();i++)
            {
            if(intersectionIntervals.get(i).val > maxValue)
            {
                maxValue=intersectionIntervals.get(i).val;
                x=intersectionIntervals.get(i);
            }
            }


        return x;
    }



}


class Interval
{
    public int a, b, val;

    public Interval(int a, int b, int val) {
        super();
        this.a = a;
        this.b = b;
        this.val = val;

    }

    @Override
    public String toString() {
        return "Interval [a=" + a + ", b=" + b + ", val=" + val + "]";
    }

    boolean isIncludedInInterval(Interval y)
    {
        //returns true if current interval is included in interval y
        return this.a>=y.a && this.b<= y.b;
    }
}

给出输出

    [0, 10, 20, 30, 40, 50, 60, 70]
[Interval [a=0, b=10, val=1], Interval [a=10, b=20, val=2], Interval [a=20, b=30, val=3], Interval [a=30, b=40, val=2], Interval [a=40, b=50, val=1], Interval [a=50, b=60, val=2], Interval [a=60, b=70, val=1]]
winning interval=Interval [a=20, b=30, val=3]

这解决了间隔是直线​​间隔而不是角度间隔的情况。考虑到 x=x+360 的事实,我会回来修改。

【讨论】:

    猜你喜欢
    • 2020-09-28
    • 2019-11-08
    • 1970-01-01
    • 2022-06-15
    • 2020-10-22
    • 1970-01-01
    • 1970-01-01
    • 2010-10-10
    • 2016-10-14
    相关资源
    最近更新 更多