最大のコストで重複しないスケジュールされたジョブを見つける


8

[開始時刻、終了時刻、コスト]のn個のジョブのセットを指定して、2つのジョブが重複せず、コストが最大になるようにサブセットを見つけます。

今、私は貪欲なアルゴリズムがうまくいくかどうかわかりません。つまり、コストで並べ替え、常に交差せず、2つの間の最大コストで次のジョブを実行します。

これはナップザック問題と同等ですか?どうすればそれにアプローチできますか?

回答:


8

重複するジョブのグラフは、間隔グラフです。区間グラフは完全なグラフです。したがって、実行しようとしているのは、完全なグラフで最大の重みに依存しないセット(つまり、2つの重複がない)を見つけることです。これは多項式時間で解決できます。アルゴリズムは、M。Grötschel、L。Lovász、およびA. Schrijverによる「完全なグラフの多項式アルゴリズム」に記載されています。

人々がこのタスクのためのより単純でより効率的なアルゴリズムを発見した完璧なグラフの特別なケースがいくつかあります。区間グラフがこれらの特殊なケースの1つに該当するかどうかはわかりません。


6

その場合、貪欲なアルゴリズムは役に立ちません。また、フラクショナルまたは0-1ナップザック問題と比較することはできませんでした。最初はO(n)の貪欲なアルゴリズムによって解決でき、2番目はNPです。

あなたが持っている問題は、O(2 ^ n)で総当たりする可能性があります。しかし、動的プログラミングを使用して最適化できます。

1)間隔を開始時間でソートします。

2)int []コスト=新しいint [jobs.length]をInteger.MIN_VALUE(または任意の負の値)で初期化します。

3)次の再帰ルーチンを定義します(ここにJavaがあります):

private int findCost(Job[] jobs, int k, int[] costs) {
   if(k >= jobs.length) {
      return 0;
   }
   if(costs[k] < 0) {
     int x = findNextCompatibleJob(jobs, k);
     int sumK = jobs[k].cost + findCost(jobs, x, costs);
     int sumK1 = findCost(jobs, k + 1, costs);
     costs[k] = Math.max(sumK, sumK1);
   }
   return costs[k];
}

private int findNextCompatibleJob(Job[] jobs, int k) {
   int finish = jobs[k].finish;
   for(int i = k + 1; i < jobs.length; i++) {
     if(jobs[i].start > finish) {
        return i;
     }
   }
   return Integer.MAX_VALUE;
}

4)k = 0で再帰を開始します。

他の部分は簡単ですが、私は再帰ルーチンのみを実装しました。コストはすべて0以上であると考えました。負のコストのジョブがある可能性がある場合は、チェックを追加して、そのジョブを考慮せずにそのまま渡す必要があります。


5

O(nlogn)でこれを実装できます

手順:

  1. 終了時間に基づいて間隔を並べ替えます
  2. 各区間に対してp(i)を定義し、i番目の区間の開始点よりも小さい最大の終了点を与えます。バイナリ検索を使用してnlognを取得する
  3. d [i] = max(w(i)+ d [p(i)]、d [i-1])を定義します。

初期化d [0] = 0

結果は、d [n] n-間隔の数になります。

全体的な複雑さO(nlogn)

import java.util.*;
class Interval {
  public int start;
  public int end;
  public int cost;
  public Interval(int start, int end, int cost){
    this.start = start;
    this.end = end;
    this.cost = cost;
  }
}
public class BestCombinationFinder {
  public int getBestCombination(List<Interval> intervals) {
    if (intervals == null || intervals.size() == 0) {
      return 0;
    }
    Collections.sort(intervals, new Comparator<Interval>() {
      public int compare(Interval i1, Interval i2) {
        if (i1.end < i2.end) {
          return -1;
        }
        else if (i1.end > i2.end) {
          return 1;
        }
        return 0;
      }
    });
    return findBestCombination(intervals);
  }
  private int findBestCombination(List<Interval> intervals) {
    int[] dp = new int[intervals.size() + 1];
    for (int i = 1; i <= intervals.size(); i++) {
      Interval currInt = intervals.get(i - 1);
      int pIndex = find(intervals, currInt.start, 0, intervals.size() - 1);
      dp[i] = Math.max(dp[pIndex+1] + currInt.cost, dp[i - 1]);
    }
    return dp[intervals.size()];
  }
  private int find(List<Interval> intervals, int target, int left, int right) {
    if (left > right) {
      return right;
    }
    else {
      int mid = (left + right) / 2;
      if (intervals.get(mid).end == target) {
        return mid;
      }
      else if (intervals.get(mid).end > target) {
        return find(intervals, target, left, mid - 1);
      }
      else {
        return find(intervals, target, mid + 1, right);
      }
    }
  }
}

2
Java(および特にJavaコレクション)を理解するように求めるのではなく、疑似コードを提供してください。
David Richerby 14

2
回答の最初の部分に疑似コードを追加しました。誰かがそれをよりよく理解するのに役立つなら、対応するJavaコードも追加したかっただけです。
シラードマンディチ2014

0

はい、それはナップザック問題と同等です。ジョブの終了時間を考慮し、ナップザックのようにテーブルを準備します。次の解決策を読む前に、ナップザックの問題とその解決策を確認してください。

// Input:
// Jobs (stored in array jobs)
// Number of jobs (n)

find the maximum end time from given n jobs => max_end

for j from 0 to max_end do
         table[0, j] := 0
end for 

for i from 1 to n do
    for j from 0 to max_end do
        if jobs[i].end <= j then
           table[i, j] := max(table[i-1, j], table[i-1, jobs[i].start] + jobs[i].cost)
       else
           table[i, j] := table[i-1, j]
       end if
    end for
 end for

テーブルをたどって、スケジュールされたジョブを印刷することもできます。

j := max_end;
for i from n to 1 do
    if table[i][j] != table[i-1][j]
        print jobs[i]
        j = jobs[i].start; 
    end if
end for

複雑さはナップザック問題と同じです。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.