2012-08-26 117 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

相關問題