我的问题与this other discussion有关。
我正在尝试使用动态程序将该算法实现为递归调用。
问题陈述:
工作j从sj
开始,在fj
结束,权重或价值为vj
。
如果两个作业不重叠,则会兼容。
目标:找到相互兼容的作业的最大权重子集。
书籍提出的解决方案是使用解决方案表来存储在递归迭代调用期间需要时重用的所有问题。
解决问题的步骤是:
Input: n, s1,...,sn , f1,...,fn , v1,...,vn
Sort jobs by finish times so that f1 > f2 >... > fn.
Compute p(1), p(2), ..., p(n)
Where p(j) = largest index i < j such that job i is compatible with j.
for j = 1 to n
M[j] = empty <-- solution table
M[j] = 0
M-Compute-Opt(j) {
if (M[j] is empty)
M[j] = max(wj + M-Compute-Opt(p(j)), M-Compute-Opt(j-1))
return M[j]
}
这是我的代码(相关部分):
全球大战:
typedef struct {
long start, stop, weight;
} job;
/* job array */
job *jobs;
/* solutions table */
long *solutions;
/* P(j) */
long *P;
- 按完成时间排序作业,以便f1&gt; f2&gt; ...&gt; FN
int compare(const void * a, const void * b) {
const job *ad = (job *) a;
const job *bd = (job *) b;
return (ad->stop - bd->stop);
}
//Jobs is filled above by parsing a datafile
qsort(jobs, njobs, sizeof(job), compare);
计算p(1),p(2),...,p(n) 其中p(j)=最大指数i < j使得作业i与j兼容。
/*bsearch for finding P(J) */
int jobsearch(int start, int high){
if (high == -1) return -1;
int low = 0;
int best = -1;
int mid;
int finish;
while (low <= high){
mid = (low + high) /2 ;
finish = jobs[mid].stop;
if (finish >= start){
high = mid-1;
}else{
best = mid;
low = mid + 1;
}
}
return best;
}
int best;
for (i = 0; i < njobs; i++){
solutions[i] = -1l; //solutions table is initialized as -1
best = jobsearch(jobs[i].start,i-1);
if (best != -1)
P[i] = best;
else
P[i] = 0;
}
M-计算-OPT(J):
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
/**
* The recursive function with the dynamic programming reduction
*/
long computeOpt(long j) {
if (j == 0)
return 0;
if (solutions[j] != -1l) {
return solutions[j];
}
solutions[j] = MAX(jobs[j].weight + computeOpt(P[j]), computeOpt(j - 1));
return solutions[j];
}
long res = computeOpt(njobs-1);
printf("%ld\n", res);
我针对具有大数据的几个测试用例(从10k到1m随机生成的作业集)运行我的程序,将我的输出与预期结果进行比较。在某些情况下,它失败了。有时我的输出有点大,有时候比预期的结果要小一些。我显然错过了一些事情。请注意,在大多数情况下我的输出是正确的,所以我认为有一些特殊情况我无法正常处理
我无法找出问题所在。
感谢任何帮助
更新 我将递归函数更改为迭代函数,现在结果对于所有测试文件都是正确的。 再一次,我无法理解为什么递归的不起作用
答案 0 :(得分:1)
让我们考虑一个小事,一个工作。你会打电话给
long res = computeOpt(njobs-1); // computeOpt(0)
然后,你有
if (j == 0)
return 0;
在computeOpt
内。所以,你不能从一份工作中获得任何收入。
一般情况下,由于上面一行,您似乎忽略了第一份工作。 if (j < 0)
应该会更好。
PS在转到“10k到1m随机生成的作业集”之前,请务必测试简单和琐碎的案例。它们更容易验证,更容易调试。