动态规划dp
d
p
[
i
]
=
m
a
x
(
d
p
[
i
−
1
]
,
d
p
[
k
]
+
p
r
o
f
i
t
[
i
−
1
]
)
dp[i]=max(dp[i−1],dp[k]+profit[i−1])
dp[i]=max(dp[i−1],dp[k]+profit[i−1])
其中 k 表示满足结束时间小于等于第 i - 1 份工作开始时间的兼职工作数量,可以通过二分查找获得。
注意:dp不仅仅可以使用时间作为i,也可以使用项目序号作为i。例如本题使用了工作的序号作为i。
本题目我卡了很久,因为没有区分清楚dp的i和jobs的i的区别,所以二分查找的时候没有搞清楚。dp是前i个工作,考察的是0~i-1的工作。
二分查找k的时候,希望的工作j应当满足end[j]<=start[i-1]。
下面代码写的二分查找,找到的是第一个大于target的序号。
所以我们找到第一个end>start[i-1]的工作的序号k,,那么0到k-1的所有工作的end都是小于start[i-1]的,所以dp[k](dp[k]考察的是0到k-1的动作)就是做工作i-1之前做的所有工作。
#define MAX(a,b) ((a)>(b)?(a):(b))
int binarySearch(const int jobs[][3],int right, int target){
int left=0;
int mid;
while(left<right){
mid=(left+right)/2;
if(jobs[mid][1]>target){
right=mid;
}
else{
left=mid+1;
}
}
return left;
}
static inline int cmp(const void *pa,const void *pb){
int* a=(int *)pa;
int *b=(int *)pb;
return a[1]-b[1];
}
int jobScheduling(int* startTime, int startTimeSize, int* endTime, int endTimeSize, int* profit, int profitSize){
int n=startTimeSize;
int jobs[n][3];
for(int i=0;i<n;i++){
jobs[i][0]=startTime[i];
jobs[i][1]=endTime[i];
jobs[i][2]=profit[i];
}
qsort(jobs,n,sizeof(jobs[0]),cmp);
int dp[n+1];
memset(dp, 0, sizeof(dp));
for(int i=1;i<=n;i++){
int k=binarySearch(jobs,i-1,jobs[i-1][0]);
dp[i]=MAX(dp[i-1],dp[k]+jobs[i-1][2]);
}
return dp[n];
}