来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/maximum-profit-in-job-scheduling
著作权归领扣网络所有。
你打算利用空闲时间来做兼职工作赚些零花钱。
这里有 n 份兼职工作,每份工作预计从 startTime[i] 开始到 endTime[i] 结束,报酬为 profit[i]。
给你一份兼职工作表,包含开始时间 startTime,结束时间 endTime 和预计报酬 profit 三个数组,请你计算并返回可以获得的最大报酬。
注意,时间上出现重叠的 2 份工作不能同时进行。
如果你选择的工作在时间 X 结束,那么你可以立刻进行在时间 X 开始的下一份工作。
示例 1:
输入:startTime = [1,2,3,3], endTime = [3,4,5,6], profit = [50,10,40,70]
输出:120
解释:
我们选出第 1 份和第 4 份工作,
时间范围是 [1-3]+[3-6],共获得报酬 120 = 50 + 70。
示例 2:
输入:startTime = [1,2,3,4,6], endTime = [3,5,10,6,9], profit = [20,20,100,70,60]
输出:150
解释:
我们选择第 1,4,5 份工作。
共获得报酬 150 = 20 + 70 + 60。
示例 3:
输入:startTime = [1,1,1], endTime = [2,3,4], profit = [5,6,4]
输出:6
https://www.bilibili.com/video/BV18x411V7fm
最开始没有根据结束时间排序,写出的代码的结果发现:
示例2=120
示例3=4
之后有看了一遍视频,发现元素是先结束时间从早到晚排列(主排序),再按开始时间的从早到晚排序(次排序)
#include
#include
typedef struct profitNode {
int startTime;
int endTime;
int profit;
} profitNode;
void print_array(int *a, int len) {
for (int i = 0; i < len; i++) {
printf("%d ", a[i]);
}
printf("\n");
}
int cmp(const void * a, const void * b) {
profitNode *A = (profitNode *)a;
profitNode *B = (profitNode *)b;
if ( A->endTime == B->endTime ) {
return A->startTime - B->startTime;
} else {
return A->endTime - B->endTime;
}
}
void sortByEndTimeAscStartTimeAsc(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int* profit, int profitSize) {
profitNode * new = (profitNode *)calloc(startTimeSize, sizeof(profitNode));
for ( int i = 0; i < startTimeSize; i++ ) {
new[i].startTime = startTime[i];
new[i].endTime = endTime[i];
new[i].profit = profit[i];
}
qsort(new, startTimeSize, sizeof(profitNode), cmp);
for ( int i = 0; i < startTimeSize; i++ ) {
startTime[i] = new[i].startTime;
endTime[i] = new[i].endTime;
profit[i] = new[i].profit;
}
free(new);
}
int *getPrev(int* startTime, int startTimeSize, int* endTime, int endTimeSize) {
int *prev = (int *) calloc(startTimeSize, sizeof(int));
for ( int i = 0; i < startTimeSize; i++ ) {
prev[i] = -1;
for ( int j = i-1; j >= 0; j-- ) {
if ( startTime[i] >= endTime[j] ) {
prev[i] = j;
break;
}
}
}
return prev;
}
int jobScheduling(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int* profit, int profitSize){
//先排序
sortByEndTimeAscStartTimeAsc(startTime, startTimeSize, endTime, endTimeSize, profit, profitSize);
int *prev = getPrev(startTime, startTimeSize, endTime, endTimeSize);
int *opt = (int *) calloc(profitSize, sizeof(int));
// opt[i] = max( profit[i] + opt(prev[i]), opt(i-1))
for (int i = 0; i < profitSize; i++) {
//不选i的价值
int notSelect = i-1 >= 0 ? opt[i-1] : 0;
//选i的价值
int select = prev[i] >= 0 ? profit[i] + opt[prev[i]] : profit[i];
opt[i] = notSelect > select ? notSelect : select;
}
print_array(prev, profitSize);
print_array(opt, profitSize);
return opt[profitSize-1];
}
int main() {
// int size = 3;
// int startTime[] = {1,1,1}, endTime[] = {2,3,4}, profit[] = {5,6,4};
// int size = 4;
// int startTime[] = {1,2,3,3}, endTime[] = {3,4,5,6}, profit[] = {50,10,40,70};
int size = 5;
int startTime[] = {1,2,3,4,6}, endTime[] = {3,5,10,6,9}, profit[] = {20,20,100,70,60};
int maxProfit = jobScheduling(startTime, size, endTime, size, profit, size);
printf("%d\n", maxProfit);
return 0;
}
/**
size=4的 示例1的执行过程
prev = -1 -1 0 0
opt = 50 50 90 120
maxProfit = 120
size=3的 示例3的执行过程
prev = -1 -1 -1
opt = 5 6 6
maxProfit = 6
size=5的 示例2的执行过程
prev = -1 -1 0 2 0
opt = 20 20 90 150 150
maxProfit = 150
*/