带权的区间调度
存在单一资源R,有n个需求{1, 2, …, n},每个需求指定一个开始时间bi与一个结束时间ei,在时间区间[bi, ei]内该需求想要占用资源R,资源R一旦被占用则无法被其他需求利用。每个需求i带有一个权值vi,代表该需求被满足之后能够带来的价值或者贡献。如果两个需求的时间区间不重叠,那么它们是相容的。带权值的区间调度问题即,对上面所描述的情境,求出一组相容子集S使得S中的区间权值之和最大。
解决此类问题一般采用动态规划的思路,执行步骤分以下几个阶段:
- 对所有的需求按照结束时间排序。
- 求出所有需求前面所有的需求中和它相容的最后一个需求,记为pi。
- 若只在前i个需求中求相容子集,则可以得到的最大权值之和为M[i],可以推导出:M[i]=max(wi+M[pi],M[i-1]),即如果最大的相容子集中包含需求i,则其权值之和为需求i的权值加上之前所有和它相容的需求子集的最大相容子集的权值之和;若不包含需求i,则其权值之和为前i-1个需求而的最大相容子集的权值之和。而应在其中取最大值,作为M[i]。
- 计算出来所有的M[i]之后,自顶而上,求出所有使权值之和变为最大的需求。
源代码
测试数据如下:
任务 | 开始时间 | 结束时间 | 重要程度 |
---|---|---|---|
0 | 0 | 4 | 2 |
1 | 1 | 6 | 4 |
2 | 5 | 7 | 4 |
3 | 2 | 9 | 7 |
4 | 8 | 10 | 2 |
5 | 8 | 11 | 1 |
测试输出如下:
( 8, 10, 2)
( 5, 7, 4)
( 0, 4, 2)
Task类
import java.util.ArrayList;
import java.util.Collections;
class Task implements Comparable<Task> {
int begin;
int end;
int weight;
int p;
public Task(int begin, int end, int weight) {
this.begin = begin;
this.end = end;
this.weight = weight;
this.p = -1;
}
public static void computeP(ArrayList<Task> tasks) {
Collections.sort(tasks);
for (int i = 0; i < tasks.size(); i++) {
for (int j = 0; j < tasks.size(); j++) {
if (tasks.get(j).begin >= tasks.get(i).end) {
tasks.get(j).p = i;
}
}
}
}
@Override
public int compareTo(Task o) {
return new Integer(end).compareTo(new Integer(o.end));
}
@Override
public String toString() {
return String.format("(%3d,%3d,%3d)", begin, end, weight);
}
}
WeightedIntervalScheduling类
import java.util.ArrayList;
public class WeightedIntervalScheduling {
private ArrayList<Task> tasks = new ArrayList<>();
private void initTasks() {
tasks.add(new Task(0, 4, 2));
tasks.add(new Task(1, 6, 4));
tasks.add(new Task(5, 7, 4));
tasks.add(new Task(2, 9, 7));
tasks.add(new Task(8, 10, 2));
tasks.add(new Task(8, 11, 1));
Task.computeP(tasks);
}
private int[] M;
private void initM() {
M = new int[tasks.size()];
for (int i = 0; i < M.length; i++) {
M[i] = -1;
}
}
public void init() {
initTasks();
initM();
}
private int M_Compute_Opt(int i) {
if (i < 0) {
return 0;
}
if (M[i] == -1) {
M[i] = Math.max(tasks.get(i).weight + M_Compute_Opt(tasks.get(i).p),
M_Compute_Opt(i - 1));
}
return M[i];
}
private void Find_Solution(int i) {
if (i < 0) {} else if (tasks.get(i).weight + M_Compute_Opt(tasks.get(i).p) >
M_Compute_Opt(i - 1)) {
System.out.println(tasks.get(i));
Find_Solution(tasks.get(i).p);
} else {
Find_Solution(i - 1);
}
}
public void Find_Solution() {
Find_Solution(tasks.size() - 1);
}
public static void main(String[] args) {
WeightedIntervalScheduling wis = new WeightedIntervalScheduling();
wis.init();
wis.Find_Solution();
}
}