Skip to content

Commit a318bf0

Browse files
committed
Renaming.
1 parent 6f6dfb8 commit a318bf0

1 file changed

Lines changed: 152 additions & 166 deletions

File tree

dynamic_programming/max_profit_in_job_scheduling.h

Lines changed: 152 additions & 166 deletions
Original file line numberDiff line numberDiff line change
@@ -4,192 +4,178 @@
44

55
#ifndef MAX_PROFIT_IN_JOB_SCHEDULING_H
66
#define MAX_PROFIT_IN_JOB_SCHEDULING_H
7-
// We have n jobs, where every job is scheduled to be done from startTime[i] to endTime[i], obtaining a profit of profit[i].
8-
// You're given the startTime, endTime and profit arrays, return the maximum profit you can take such that there are no
9-
// two jobs in the subset with overlapping time range.
10-
// If you choose a job that ends at time X you will be able to start another job that starts at time X.
11-
#include <vector>
7+
// We have n jobs, where every job is scheduled to be done from startTime[i] to
8+
// endTime[i], obtaining a profit of profit[i]. You're given the startTime,
9+
// endTime and profit arrays, return the maximum profit you can take such that
10+
// there are no two jobs in the subset with overlapping time range. If you
11+
// choose a job that ends at time X you will be able to start another job that
12+
// starts at time X.
1213
#include <algorithm>
14+
#include <vector>
1315

14-
struct Job
15-
{
16-
int start;
17-
int end;
18-
int profit;
16+
struct Job {
17+
int start;
18+
int end;
19+
int profit;
1920
};
2021

21-
int find_next_job(const std::vector<Job>& jobs, int current_end)
22-
{
23-
int low = 0;
24-
int high = jobs.size();
25-
while (low < high)
26-
{
27-
const int mid = (low + high) / 2;
28-
if (jobs[mid].start >= current_end)
29-
high = mid;
30-
else
31-
low = mid + 1;
32-
}
33-
return low;
22+
int find_next_job(const std::vector<Job> &jobs, int current_end) {
23+
int low = 0;
24+
int high = jobs.size();
25+
while (low < high) {
26+
const int mid = (low + high) / 2;
27+
if (jobs[mid].start >= current_end)
28+
high = mid;
29+
else
30+
low = mid + 1;
31+
}
32+
return low;
3433
}
3534

3635
// Binary search to find the last job that doesn't overlap
37-
int find_last_non_conflicting(const std::vector<Job>& jobs, int job_index)
38-
{
39-
int low = 0;
40-
int high = job_index - 1;
41-
while (low <= high)
42-
{
43-
const int mid = (low + high) / 2;
44-
if (jobs[mid].end <= jobs[job_index].start)
45-
{
46-
if (jobs[mid + 1].end <= jobs[job_index].start)
47-
low = mid + 1;
48-
else
49-
return mid;
50-
}
51-
else
52-
high = mid - 1;
53-
}
54-
return -1;
36+
int find_last_non_conflicting(const std::vector<Job> &jobs, int job_index) {
37+
int low = 0;
38+
int high = job_index - 1;
39+
while (low <= high) {
40+
const int mid = (low + high) / 2;
41+
if (jobs[mid].end <= jobs[job_index].start) {
42+
if (jobs[mid + 1].end <= jobs[job_index].start)
43+
low = mid + 1;
44+
else
45+
return mid;
46+
} else
47+
high = mid - 1;
48+
}
49+
return -1;
5550
}
5651

57-
int dp(int job_index, const std::vector<Job>& jobs, std::vector<int>& memo)
58-
{
59-
if (job_index >= jobs.size())
60-
return 0;
61-
if (memo[job_index] != -1)
62-
return memo[job_index];
63-
int next = find_next_job(jobs, jobs[job_index].end);
64-
int take_next_job = jobs[job_index].profit + dp(next, jobs, memo);
65-
int skip_next_job = dp(job_index + 1, jobs, memo);
66-
67-
return memo[job_index] = std::max(take_next_job, skip_next_job);
52+
int dp(int job_index, const std::vector<Job> &jobs, std::vector<int> &memo) {
53+
if (job_index >= jobs.size())
54+
return 0;
55+
if (memo[job_index] != -1)
56+
return memo[job_index];
57+
int next = find_next_job(jobs, jobs[job_index].end);
58+
int take_next_job = jobs[job_index].profit + dp(next, jobs, memo);
59+
int skip_next_job = dp(job_index + 1, jobs, memo);
60+
61+
return memo[job_index] = std::max(take_next_job, skip_next_job);
6862
}
6963

7064
// top-down approach
71-
int job_scheduling(std::vector<int>& start_time, std::vector<int>& end_time, std::vector<int>& profit)
72-
{
73-
int n = start_time.size();
74-
if (n == 0)
75-
return 0;
76-
std::vector<Job> jobs(n);
77-
for (int i = 0; i < n; i++)
78-
{
79-
jobs[i] = {start_time[i], end_time[i], profit[i]};
80-
}
81-
std::sort(jobs.begin(), jobs.end(), [](const Job& j1, const Job& j2)
82-
{
83-
return j1.start < j2.start;
84-
});
85-
std::vector<int> memo(n, -1);
86-
return dp(0, jobs, memo);
65+
int job_scheduling(std::vector<int> &start_time, std::vector<int> &end_time,
66+
std::vector<int> &profit) {
67+
int n = start_time.size();
68+
if (n == 0)
69+
return 0;
70+
std::vector<Job> jobs(n);
71+
for (int i = 0; i < n; i++) {
72+
jobs[i] = {start_time[i], end_time[i], profit[i]};
73+
}
74+
std::sort(jobs.begin(), jobs.end(),
75+
[](const Job &j1, const Job &j2) { return j1.start < j2.start; });
76+
std::vector<int> memo(n, -1);
77+
return dp(0, jobs, memo);
8778
}
8879

8980
// bottom-up approach
90-
int job_scheduling_bottom_up(std::vector<int>& start_time, std::vector<int>& end_time, std::vector<int>& profit)
91-
{
92-
int n = start_time.size();
93-
if (n == 0)
94-
return 0;
95-
std::vector<Job> jobs(n);
96-
for (int i = 0; i < n; i++)
97-
{
98-
jobs[i] = {start_time[i], end_time[i], profit[i]};
99-
}
100-
std::sort(jobs.begin(), jobs.end(), [](const Job& j1, const Job& j2)
101-
{
102-
return j1.end < j2.end;
103-
});
104-
std::vector<int> dp(n);
105-
dp[0] = jobs[0].profit;
106-
for (int job_index = 1; job_index < n; ++job_index)
107-
{
108-
int profit_if_taken = jobs[job_index].profit;
109-
110-
int last_compatible_index = find_last_non_conflicting(jobs, job_index);
111-
if (last_compatible_index != -1)
112-
{
113-
profit_if_taken += dp[last_compatible_index];
114-
}
115-
116-
dp[job_index] = std::max(dp[job_index - 1], profit_if_taken);
81+
int job_scheduling_bottom_up(std::vector<int> &start_time,
82+
std::vector<int> &end_time,
83+
std::vector<int> &profit) {
84+
int n = start_time.size();
85+
if (n == 0)
86+
return 0;
87+
std::vector<Job> jobs(n);
88+
for (int i = 0; i < n; i++) {
89+
jobs[i] = {start_time[i], end_time[i], profit[i]};
90+
}
91+
std::sort(jobs.begin(), jobs.end(),
92+
[](const Job &j1, const Job &j2) { return j1.end < j2.end; });
93+
std::vector<int> dp(n);
94+
dp[0] = jobs[0].profit;
95+
for (int job_index = 1; job_index < n; ++job_index) {
96+
int profit_if_taken = jobs[job_index].profit;
97+
98+
int last_compatible_index = find_last_non_conflicting(jobs, job_index);
99+
if (last_compatible_index != -1) {
100+
profit_if_taken += dp[last_compatible_index];
117101
}
118102

119-
return dp[n - 1];
120-
}
121-
103+
dp[job_index] = std::max(dp[job_index - 1], profit_if_taken);
104+
}
122105

123-
int compact_top_down(const std::vector<int> & start, const std::vector<int> & end, std::vector<int> & profit)
124-
{
125-
struct Job
126-
{
127-
int s;
128-
int e;
129-
int p;
130-
};
131-
int n = start.size();
132-
std::vector<Job> jobs(n);
133-
for (int i{}; i < n; ++i)
134-
{
135-
jobs[i] = {start[i], end[i], profit[i]};
136-
}
137-
std::sort(jobs.begin(), jobs.end(), [](const Job& j1, const Job& j2){ return j1.s < j2.s; });
138-
std::vector<int> sorted_starts(n);
139-
for (int i{}; i < n; ++i)
140-
{
141-
sorted_starts[i] = jobs[i].s;
142-
}
143-
std::vector<int> memo(n ,-1);
144-
145-
std::function<int(int)> dfs = [&](int i)-> int
146-
{
147-
if (i>n-1)
148-
return 0;
149-
if (memo[i] != -1)
150-
return memo[i];
151-
int best = dfs(i+1);
152-
int j = int(std::lower_bound(sorted_starts.begin(), sorted_starts.end(), jobs[i].e) - sorted_starts.begin());
153-
best = std::max(best, jobs[i].p + dfs(j));
154-
return memo[i] = best;
155-
};
156-
return dfs(0);
106+
return dp[n - 1];
157107
}
158108

109+
int compact_top_down(const std::vector<int> &start, const std::vector<int> &end,
110+
std::vector<int> &profit) {
111+
struct Job {
112+
int start;
113+
int end;
114+
int profit;
115+
};
116+
int n = start.size();
117+
std::vector<Job> jobs(n);
118+
for (int i{}; i < n; ++i) {
119+
jobs[i] = {start[i], end[i], profit[i]};
120+
}
121+
std::sort(jobs.begin(), jobs.end(),
122+
[](const Job &j1, const Job &j2) { return j1.start < j2.start; });
123+
std::vector<int> sorted_starts(n);
124+
for (int i{}; i < n; ++i) {
125+
sorted_starts[i] = jobs[i].start;
126+
}
127+
std::vector<int> memo(n, -1);
128+
129+
std::function<int(int)> dfs = [&](int current_job_index) -> int {
130+
if (current_job_index > n - 1)
131+
return 0;
132+
if (memo[current_job_index] != -1)
133+
return memo[current_job_index];
134+
// skip i, walk down all the way to n, dfs-like
135+
int best = dfs(current_job_index + 1);
136+
// take i: jump to first job with start >= jobs[i].e, i is the current
137+
int next_job_index =
138+
int(std::lower_bound(sorted_starts.begin(), sorted_starts.end(),
139+
jobs[current_job_index].end) -
140+
sorted_starts.begin());
141+
best = std::max(best, jobs[current_job_index].profit + dfs(next_job_index));
142+
return memo[current_job_index] = best;
143+
};
144+
return dfs(0);
145+
}
159146

160-
int compact_bottom_up(const std::vector<int> & start, const std::vector<int> & end, std::vector<int> & profit)
161-
{
162-
struct Job
163-
{
164-
int s;
165-
int e;
166-
int p;
167-
};
168-
int n = start.size();
169-
std::vector<Job> jobs(n);
170-
for (int i{}; i < n; ++i)
171-
{
172-
jobs[i] = {start[i], end[i], profit[i]};
173-
}
174-
std::sort(jobs.begin(), jobs.end(), [](const Job& j1, const Job& j2){ return j1.e < j2.e; });
175-
176-
std::vector<int> sorted_ends(n);
177-
for (int i{}; i < n; ++i)
178-
{
179-
sorted_ends[i] = jobs[i].e;
180-
}
181-
auto pred = [&](int i)-> int
182-
{
183-
return int(std::upper_bound(sorted_ends.begin(), sorted_ends.end(), jobs[i].s) - sorted_ends.begin()) - 1;
184-
};
185-
std::vector<int> dp(n+1, 0);
186-
for (int i=1; i <= n; ++i)
187-
{
188-
int j =pred(i-1);
189-
int take = jobs[i-1].p + dp[j+1];
190-
dp[i] = std::max(dp[i-1], take);
191-
}
192-
return dp[n];
147+
int compact_bottom_up(const std::vector<int> &start,
148+
const std::vector<int> &end, std::vector<int> &profit) {
149+
struct Job {
150+
int start;
151+
int end;
152+
int profit;
153+
};
154+
int n = start.size();
155+
std::vector<Job> jobs(n);
156+
for (int i{}; i < n; ++i) {
157+
jobs[i] = {start[i], end[i], profit[i]};
158+
}
159+
std::sort(jobs.begin(), jobs.end(),
160+
[](const Job &j1, const Job &j2) { return j1.end < j2.end; });
161+
162+
std::vector<int> sorted_ends(n);
163+
for (int i{}; i < n; ++i) {
164+
sorted_ends[i] = jobs[i].end;
165+
}
166+
auto pred = [&](int i) -> int {
167+
return int(std::upper_bound(sorted_ends.begin(), sorted_ends.end(),
168+
jobs[i].start) -
169+
sorted_ends.begin()) -
170+
1;
171+
};
172+
std::vector<int> dp(n + 1, 0);
173+
for (int i = 1; i <= n; ++i) {
174+
int j = pred(i - 1);
175+
int take = jobs[i - 1].profit + dp[j + 1];
176+
dp[i] = std::max(dp[i - 1], take);
177+
}
178+
return dp[n];
193179
}
194180

195-
#endif //MAX_PROFIT_IN_JOB_SCHEDULING_H
181+
#endif // MAX_PROFIT_IN_JOB_SCHEDULING_H

0 commit comments

Comments
 (0)