2012-08-26 75 views
3

我正试图确定这个难题的最佳解决方案。我有一个长度(比如说11)。所以这是一个0-10的一维空间。现在我已经得到了这些间隔相同长度(让我们假设2在这个例子中)。现在它们是随机分布的(重叠或不重叠)。让我来举一个例子:如何确定给定范围内的最佳间隔数?

Situation: 

|00|01|02|03|04|05|06|07|08|09|10| <- Space (length = 11) 

|-----|  
     |-----| 
      |-----| 
       |-----| 
        |-----| 
          |-----| <- single interval of length = 2 

现在解决方案需要找到一次可以适合的最大数量的间隔,而不会重叠。

The solution is: 4 intervals 

有4个间隔时间三种结果:

|00|01|02|03|04|05|06|07|08|09|10| 

|-----| |-----|-----|  |-----| <- result 1 
|-----| |-----| |-----| |-----| <- result 2 
|-----|  |-----|-----| |-----| <- result 3 

但也有两个限制为好。

  1. 如果有更多的结果(最好的解决方案的,在这种情况下= 4),那么一个具有间隙的数量最少。

  2. 如果还有更多的结果仍然是所有空间的最小长度最长的结果。例如,该酮与2- & 3(长度)的空间具有的空间= 2的最小长度,即优于1 & 4,其中的空间的最小长度仅为1

所以结果2具有4“连续”块,其他两个只有3个这样的改进是:

|00|01|02|03|04|05|06|07|08|09|10| 

|-----| |-----------|  |-----| <- result 1 
|-----|  |-----------| |-----| <- result 3 

这两个得到了他们之间相同的空间分布,所以让我们第一个。

用于输入集合的结果是:

Interval count : 4 
Optimal solution: |-----| |-----------|  |-----| 

该算法具有普遍用于所有的空间长度工作(不仅11),所有的间隔长度(间隔长度总是< =空白长度)和任何数量的间隔。

更新:

有问题的情景:

|00|01|02|03|04|05|06|07|08|09| 

|-----| 
     |-----| 
      |-----|  
         |-----| 
|-----| 
+1

有趣。但你的尝试在哪里? –

+0

一个很好的问题,但我认为它不适合SO。 –

+0

你是否试图靠某种方式来成功? 伙计,这不是欧拉项目。 – Vitaliy

回答

3

这是一个简单的动态规划问题。

设总长度为N,任务长度为L

F(T)是能够从子间隔(T, N)被选择的任务的最大数量,则每单位时间T处,有3种可能性:

  1. 没有开始于T.
  2. 任务
  3. 有一项任务从T开始,但我们不会将其包含在结果集中。
  4. 有一个任务从T开始,我们将它包含在结果集中。

案例1很简单,我们只有F(T) = F(T + 1)

在2/3的情况下,注意选择是开始T意味着我们必须拒绝接受这个任务运行时,即TT + L之间的启动所有任务的任务。所以我们得到F(T) = max(F(T + 1), F(T + L) + 1)

最后,F(N) = 0。所以你只需从F(N)开始,然后回到F(0)

编辑:这将给你最大间隔数,但不是满足你的2个约束的集合。您对约束条件的解释不清楚,所以我不确定如何在那里帮助您。特别是,我不能说出什么是约束条件,因为你的示例集合的所有解决方案显然是相同的。

编辑2:所要求的一些进一步的解释:

考虑您发布的例子,我们有N = 11L = 2。有些任务开始于T = 0, 3, 4, 5, 6, 9。从F(11) = 0开始和向后工作:

  • F(11) = 0
  • F(10) = F(11) = 0(由于没有任务开始T = 10
  • F(9) = max(F(10), F(11) + 1) = 1
  • ...

最终我们得到F(0) = 4

T |00|01|02|03|04|05|06|07|08|09|10| 
F(T)| 4| 3| 3| 3| 3| 2| 2| 1| 1| 1| 0| 

编辑3:好吧,我很好奇这件事,所以我写了一个解决方案,所以不妨将它发布。这将为您提供具有最多任务,最少差距和最小最小差距的集合。在讨论的例子输出是:

  • (0, 2) -> (4, 6) -> (6, 8) -> (9, 11)
  • (0, 2) -> (4, 6) -> (8, 10)

很显然,我做出的正确性任何保证! :)

私人课程任务 public int Start {get;组; } public int Length {get;组; } public int End {get {return Start + Length; }}

public override string ToString() 
    { 
     return string.Format("({0:d}, {1:d})", Start, End); 
    } 
} 

private class CacheEntry : IComparable 
{ 
    public int Tasks { get; set; } 
    public int Gaps { get; set; } 
    public int MinGap { get; set; } 
    public Task Task { get; set; } 
    public Task NextTask { get; set; } 

    public int CompareTo(object obj) 
    { 
     var other = obj as CacheEntry; 
     if (Tasks != other.Tasks) 
      return Tasks - other.Tasks; // More tasks is better 
     if (Gaps != other.Gaps) 
      return other.Gaps = Gaps; // Less gaps is better 
     return MinGap - other.MinGap; // Larger minimum gap is better 
    } 
} 

private static IList<Task> F(IList<Task> tasks) 
{ 
    var end = tasks.Max(x => x.End); 
    var tasksByTime = tasks.ToLookup(x => x.Start); 
    var cache = new List<CacheEntry>[end + 1]; 

    cache[end] = new List<CacheEntry> { new CacheEntry { Tasks = 0, Gaps = 0, MinGap = end + 1 } }; 

    for (int t = end - 1; t >= 0; t--) 
    { 
     if (!tasksByTime.Contains(t)) 
     { 
      cache[t] = cache[t + 1]; 
      continue; 
     } 

     foreach (var task in tasksByTime[t]) 
     { 
      var oldCEs = cache[t + task.Length]; 
      var firstOldCE = oldCEs.First(); 
      var lastOldCE = oldCEs.Last(); 

      var newCE = new CacheEntry 
      { 
       Tasks = firstOldCE.Tasks + 1, 
       Task = task, 
       Gaps = firstOldCE.Gaps, 
       MinGap = firstOldCE.MinGap 
      }; 

      // If there is a task that starts at time T + L, then that will always 
      // be the best option for us, as it will have one less Gap than the others 
      if (firstOldCE.Task == null || firstOldCE.Task.Start == task.End) 
      { 
       newCE.NextTask = firstOldCE.Task; 
      } 
      // Otherwise we want the one that maximises MinGap. 
      else 
      { 
       var ce = oldCEs.OrderBy(x => Math.Min(x.Task.Start - newCE.Task.End, x.MinGap)).Last(); 
       newCE.NextTask = ce.Task; 
       newCE.Gaps++; 
       newCE.MinGap = Math.Min(ce.MinGap, ce.Task.Start - task.End); 
      } 

      var toComp = cache[t] ?? cache[t + 1]; 
      if (newCE.CompareTo(toComp.First()) < 0) 
      { 
       cache[t] = toComp; 
      } 
      else 
      { 
       var ceList = new List<CacheEntry> { newCE }; 

       // We need to keep track of all subsolutions X that start on the interval [T, T+L] that 
       // have an equal number of tasks and gaps, but a possibly a smaller MinGap. This is 
       // because an earlier task may have an even smaller gap to this task. 
       int idx = newCE.Task.Start + 1; 
       while (idx < newCE.Task.End) 
       { 
        toComp = cache[idx]; 
        if 
        (
         newCE.Tasks == toComp.First().Tasks && 
         newCE.Gaps == toComp.First().Gaps && 
         newCE.MinGap >= toComp.First().MinGap 
        ) 
        { 
         ceList.AddRange(toComp); 
         idx += toComp.First().Task.End; 
        } 
        else 
         idx++; 
       } 

       cache[t] = ceList; 
      } 
     } 
    } 

    var rv = new List<Task>(); 
    var curr = cache[0].First(); 
    while (true) 
    { 
     rv.Add(curr.Task); 
     if (curr.NextTask == null) break; 
     curr = cache[curr.NextTask.Start].First(); 
    } 

    return rv; 
} 

public static void Main() 
{ 
    IList<Task> tasks, sol; 

    tasks = new List<Task> 
    { 
     new Task { Start = 0, Length = 2 }, 
     new Task { Start = 3, Length = 2 }, 
     new Task { Start = 4, Length = 2 }, 
     new Task { Start = 5, Length = 2 }, 
     new Task { Start = 6, Length = 2 }, 
     new Task { Start = 9, Length = 2 }, 
    }; 

    sol = F(tasks); 
    foreach (var task in sol) 
     Console.Out.WriteLine(task); 
    Console.Out.WriteLine(); 

    tasks = new List<Task> 
    { 
     new Task { Start = 0, Length = 2 }, 
     new Task { Start = 3, Length = 2 }, 
     new Task { Start = 4, Length = 2 }, 
     new Task { Start = 8, Length = 2 }, 
    }; 

    sol = F(tasks); 
    foreach (var task in sol) 
     Console.Out.WriteLine(task); 
    Console.Out.WriteLine(); 

    tasks = new List<Task> 
    { 
     new Task { Start = 0, Length = 5 }, 
     new Task { Start = 6, Length = 5 }, 
     new Task { Start = 7, Length = 3 }, 
     new Task { Start = 8, Length = 9 }, 
     new Task { Start = 19, Length = 1 }, 
    }; 

    sol = F(tasks); 
    foreach (var task in sol) 
     Console.Out.WriteLine(task); 
    Console.Out.WriteLine(); 

    Console.In.ReadLine(); 
} 
+0

时间/任务的影响令我感到困惑。但即使我可能需要更多的解释比这个。你能告诉我它将如何发挥出来吗?我的意思是画几个步骤,所以我能够得到发生了什么? – SmartK8

+0

@ SmartK8当我说'任务'时,我指的是原始问题陈述中的一个间隔。我使用“时间”来表示间隔开始的时间点,例如你的例子有在时间0,3,4,5,6和9开始的任务。 – verdesmarald

+0

好的,但是你能告诉我几次第一次迭代的结果。对我来说,赶上你的解决方案? – SmartK8

相关问题