寻找与所有弧相交的最小光线数

时间:2016-12-29 06:22:06

标签: algorithm greedy

在编程访谈元素中有一个问题我试图解决但是没有成功。 假设我们得到一个(d1, d2)形式的区间数组,其中d1d2是表示弧的起点和终点角度的度数值,其中0度是y轴。这些间隔可以重叠,您可以使用(350, 10)之间的间隔。您可以拍摄的所有间隔相交的最小光线数是多少?光线可以表示为与y轴成角度的角度。

我尝试按端点排序并查看每个端点是否与下一个间隔相交,但我无法弄清楚如何处理重叠间隔,例如(340, 350), (350, 20)

3 个答案:

答案 0 :(得分:0)

为了优化弧的数量,例如,如果A和C相交,则不能将光线从A投射到B,而另一条光线则从C到D投射。

关键点是找到弧之间的所有交点(并按属于更多弧的点对它们进行排序)。

对它们进行排序后,获取属于更多弧线的角度,并将光线从其设置为另一个属于不同于第一个弧线的其他弧线的点。最不同的,更好的。你可以只是旅行角度并检查最适合的角度。

答案 1 :(得分:0)

  1. 创建所有使用角度(间隔边缘)的表格let cell: AvailableCoursesSecondViewControllerTableViewCell = (NSBundle.mainBundle().loadNibNamed("AvailableCoursesSecondViewControllerTableViewCell", owner: self, options: nil).first as? AvailableCoursesSecondViewControllerTableViewCell)! let model = myDataSource.availableCourses[indexPath.row] // All classList item, as array collection type, at a given indexPath let classList: [classListDetailModel] = model.categoryData.classList classList.forEach { (classListItem) in // Each classListDetailModel item printed print(classListItem) }

    应仅包含不同的角度

  2. 将所有弧线设置为未使用

  3. tab找到与大多数未使用的弧相交的角度
  4. 将其添加为光线
  5. tab
  6. 中排除此角度
  7. 设置所有相交的光线
  8. 循环#2,直到没有未使用的弧或角度
  9. 这将显着减少光线数量,但无法确保最佳解决方案!要获得最佳解决方案,您需要使用 genere& amp;测试方法。这里有一些 C ++ 代码:

    tab

    概述:

    overview

    正如你所看到的那样,如果你需要不同的光线,你可以通过边缘点投射光线,你需要稍微调整一下(比如使用普通重叠的中间角度会导致更多的粗糙光线)。代码远未优化我现在编写它只是为了好玩...

    为了改善这一点,您可以对列表进行排序并改为使用远程搜索(类似于合并排序列表)在当前的代码状态中,排序没有任何优势......

答案 2 :(得分:0)

假设度数是整数:

  1. 循环查找所有-1起始角和+1结束角的度数
  2. 将圆弧视为间隔,搜索是否有从 1. 开始的点未覆盖
  3. 如果是,我们将使用该点开始采取最佳策略的贪婪策略
  4. 如果没有 - 则返回覆盖 1 中所有点的最小区间集。从考虑中删除这些区间并尝试找到没有这些区间的起点,从那里开始并在 3 中使用相同的贪婪策略,合并结果返回删除间隔的最佳结果。

例如

def algo:
  results = [] # will be an array of angles that represent the best shots
  I = [(start,end)] #array of starting and ending degrees
  P = getAnglesOutOfRange() # where this func just returns an array of points
                            # which are not covered by the starting and ending
                            # angles in I (+1 starting, -1 ending) mod 360
  
  obj = intervalPointCoverForArcs(P,I) 

  # if obj is a point than we have the starting point to start shooting.
  # Sort intervals by ascending starting angle, then iterate over queue
  # performing greedy strategy of shooting just inside the least ending angle
  # of overlapping intervals. 

  # if obj is a set of intervals than remove those intervals from I and recursively
  # call this function - the recursive call will return a list of
  # angles which will make up the best shots for the subset of intervals.
  # Perform a merge operation to determine which intervals still need to be covered 
  # by a point and remove those intervals with the same greedy strategy. 

return results

def intervalPointCoverForArcs(P,I):
  # Were P is a set of points and I is a set of intervals
  results = []; Last = -inf; end_init = -inf;
  I_max = SelectMax(I)  # Function that grabs the interval with the latest starting
                        # angle.
                        # We choose starting angle because we want to see if the ending
                        # angle crosses the 0 axis.
  if I_max.end > 360: 
    end_init = I_max.end # Tracking that this interval overlaps the 0 axis
                         # So any points less than this amount will be covered
    
    I_max.end = I_max.end + 360 # increasing the initial intervals' ending value 
                                # to go past 0 axis
  
  I_init = (-inf,end_init) # this will be the first item deleted from the items
                           # PriorityQueue below since it's starting angle is initialized
                           # to -inf
  I.append(I_init)
  activated_intervals = PriorityQueue() # Empty queue to start - queue will be sorted by
                                       # descending ending angles
  items = PriorityQueue(I,P) # Function which combines the Intervals and Points returning
                             # an ascending sorted order of points and 
                             # interval starting angle
  while not items.isEmpty():
    i = items.delete()
    
    if isinstance(i, set): 
      activated_intervals.insert(i)
    elif i > Last: 
      k = activated_intervals.delete()
      
      if k.end < i: 
        return i # this is our starting point as no interval covers it
      else:
        Last = k.end
        result.append(k)  # Track this interval as it's covering the most points and
                          # we may want to remove later in case all the points are covered
  return results