Skip to content

Commit df8b273

Browse files
authored
Create README.md
1 parent 67f1a43 commit df8b273

File tree

1 file changed

+365
-0
lines changed
  • 25 - Greedy Algorithm Problems/11 - Job Sequencing Problem

1 file changed

+365
-0
lines changed
Lines changed: 365 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,365 @@
1+
<h1 align="center">Job - Sequencing - Problem</h1>
2+
3+
## Problem Statement
4+
5+
**Problem URL :** [Job Sequencing Problem](https://www.geeksforgeeks.org/problems/job-sequencing-problem-1587115620/1)
6+
7+
![image](https://github.com/user-attachments/assets/a0836399-100c-4af5-b3f7-23c682a557bb)
8+
9+
### Problem Explanation
10+
The **Job Sequencing Problem** is a classic problem where you are given a list of jobs, and each job has:
11+
- A deadline, indicating by which time the job should be completed.
12+
- A profit that will be earned if the job is completed before or at its deadline.
13+
14+
The goal is to **schedule the jobs** in such a way that the total profit is maximized. Additionally, the jobs need to be scheduled in a way that **no two jobs overlap**.
15+
16+
#### Problem Input:
17+
18+
- `id[]`: A list of unique job identifiers.
19+
- `deadline[]`: A list of deadlines corresponding to the jobs.
20+
- `profit[]`: A list of profits corresponding to the jobs.
21+
22+
#### Problem Output:
23+
24+
- The **maximum profit** that can be earned by scheduling jobs before or at their deadlines.
25+
- The **number of jobs** scheduled.
26+
27+
#### Constraints:
28+
29+
- The job id is a unique number.
30+
- A job should be completed before or at its given deadline.
31+
- A job can only be scheduled if there is a free slot available before or at its deadline.
32+
33+
#### Example:
34+
35+
Consider the following job list:
36+
37+
| Job ID | Deadline | Profit |
38+
|--------|----------|--------|
39+
| 1 | 4 | 20 |
40+
| 2 | 1 | 10 |
41+
| 3 | 1 | 40 |
42+
| 4 | 1 | 30 |
43+
44+
#### Step-by-Step Explanation:
45+
46+
##### Step 1: Sort jobs by profit in descending order
47+
To maximize the profit, we start by sorting the jobs based on their profit in descending order. The reason for this is that we want to prioritize jobs with higher profit.
48+
49+
**Sorted jobs by profit:**
50+
51+
| Job ID | Deadline | Profit |
52+
|--------|----------|--------|
53+
| 3 | 1 | 40 |
54+
| 1 | 4 | 20 |
55+
| 4 | 1 | 30 |
56+
| 2 | 1 | 10 |
57+
58+
##### Step 2: Find the maximum deadline
59+
The maximum deadline is `4`, which means that we need to create an array of slots from `1` to `4`.
60+
61+
##### Step 3: Create an array to track scheduled jobs
62+
We initialize an array `schedule[]` where the index represents time slots. Initially, the slots are empty (i.e., `-1`).
63+
64+
**schedule[] (initial):** `[-1, -1, -1, -1]`
65+
66+
##### Step 4: Iterate through sorted jobs
67+
Now, we iterate through the sorted jobs and try to place each job in the last available slot before its deadline. If a slot is available, we schedule the job in that slot.
68+
69+
- **Job 3** (Profit 40, Deadline 1): We check slot `1`. Since it's empty, we place Job 3 in slot `1`. The profit is now `40`, and one job is scheduled.
70+
71+
**schedule[]:** `[3, -1, -1, -1]`
72+
73+
- **Job 1** (Profit 20, Deadline 4): We check slot `4`. Since it's empty, we place Job 1 in slot `4`. The profit is now `60`, and two jobs are scheduled.
74+
75+
**schedule[]:** `[3, -1, -1, 1]`
76+
77+
- **Job 4** (Profit 30, Deadline 1): We check slot `1`, but slot `1` is already occupied by Job 3. We then check slot `0`, but since this is out of bounds, Job 4 cannot be scheduled.
78+
79+
**schedule[] remains:** `[3, -1, -1, 1]`
80+
81+
- **Job 2** (Profit 10, Deadline 1): We check slot `1`, but slot `1` is already occupied by Job 3. We check slot `0`, but it is out of bounds. Job 2 cannot be scheduled either.
82+
83+
**schedule[] remains:** `[3, -1, -1, 1]`
84+
85+
##### Step 5: Return the result
86+
- The total number of jobs scheduled is `2`.
87+
- The total profit earned is `40 + 20 = 60`.
88+
89+
#### Final Output:
90+
91+
- **Number of jobs scheduled:** 2
92+
- **Total profit:** 60
93+
94+
### Greedy Algorithm Approach
95+
96+
##### Step 1: Sort the jobs by profit
97+
We first sort the jobs in descending order of profit. This ensures that we try to schedule the most profitable jobs first, which helps in maximizing the total profit.
98+
99+
##### Step 2: Find the maximum deadline
100+
We need to determine the latest deadline because that defines the size of the array we use to track scheduled jobs. The size of the `schedule[]` array will be equal to the maximum deadline, and it helps us know how many available time slots we have.
101+
102+
##### Step 3: Schedule jobs in available slots
103+
We then iterate over the sorted jobs:
104+
- For each job, we try to find a time slot that is available before or at the job's deadline.
105+
- If we find an available slot, we schedule the job there and update the `schedule[]` array to mark that slot as occupied.
106+
- If no slot is available, we move on to the next job.
107+
108+
##### Step 4: Calculate the result
109+
Once all jobs have been considered, we calculate:
110+
- The total number of jobs that were scheduled (count of jobs in the `schedule[]` array).
111+
- The total profit earned from these scheduled jobs.
112+
113+
##### Step 5: Return the result
114+
Finally, we return the total number of jobs scheduled and the total profit.
115+
116+
## Problem Solution
117+
```cpp
118+
class Solution {
119+
public:
120+
vector<int> JobSequencing(vector<int> &id, vector<int> &deadline,
121+
vector<int> &profit) {
122+
123+
// Step 1: Create a vector of tuples to store job details (profit, job id, and deadline)
124+
vector<tuple<int, int, int>> v;
125+
126+
// Loop through the job arrays and create tuples of (profit, job id, deadline)
127+
for(int i = 0; i < id.size(); i++){
128+
v.push_back(make_tuple(profit[i], id[i], deadline[i]));
129+
}
130+
131+
// Step 2: Sort the jobs by profit in descending order
132+
// The job with higher profit is considered first
133+
sort(v.begin(), v.end(), [](tuple<int, int, int>& a, tuple<int, int, int>& b){
134+
return get<0>(a) > get<0>(b); // Compare based on profit (first element of the tuple)
135+
});
136+
137+
// Step 3: Find the maximum deadline to define the size of the schedule array
138+
int maxiDeadline = INT_MIN;
139+
for(int i = 0; i < deadline.size(); i++){
140+
maxiDeadline = max(maxiDeadline, deadline[i]);
141+
}
142+
143+
// Step 4: Initialize the schedule array with -1 to represent unoccupied time slots
144+
// The array has size `maxiDeadline + 1` because deadlines are 1-based.
145+
vector<int> schedule(maxiDeadline+1, -1);
146+
147+
// Step 5: Initialize variables to track the number of jobs selected and total profit
148+
int count = 0;
149+
int maxProfit = 0;
150+
151+
// Step 6: Try to schedule jobs in decreasing order of their profit
152+
for(int i = 0; i < v.size(); i++){
153+
int currProfit = get<0>(v[i]); // Profit of the current job
154+
int currJobId = get<1>(v[i]); // Job id of the current job
155+
int currDeadline = get<2>(v[i]); // Deadline of the current job
156+
157+
// Step 7: Try to find the latest available time slot before the job's deadline
158+
for(int k = currDeadline; k > 0; k--){
159+
// If the time slot is free (schedule[k] == -1), schedule the job there
160+
if(schedule[k] == -1){
161+
schedule[k] = currJobId; // Assign the job id to the available slot
162+
maxProfit += currProfit; // Add the profit of the job to the total profit
163+
count++; // Increment the count of scheduled jobs
164+
break; // Break out of the loop after scheduling the job
165+
}
166+
}
167+
}
168+
169+
// Step 8: Return the count of jobs scheduled and the total profit
170+
return {count, maxProfit};
171+
}
172+
};
173+
174+
```
175+
176+
## Problem Solution Explanation
177+
#### 1. **Function Declaration:**
178+
179+
```cpp
180+
vector<int> JobSequencing(vector<int> &id, vector<int> &deadline, vector<int> &profit) {
181+
```
182+
183+
- This function is part of a class `Solution` and takes three parameters:
184+
- `id[]`: A vector containing job identifiers (ID of each job).
185+
- `deadline[]`: A vector containing the deadlines for each job.
186+
- `profit[]`: A vector containing the profit associated with each job.
187+
188+
It returns a vector of two integers: the count of jobs scheduled and the maximum profit earned.
189+
190+
191+
#### 2. **Creating the Vector of Tuples:**
192+
193+
```cpp
194+
vector<tuple<int, int, int>> v;
195+
```
196+
197+
- Here, a `vector` named `v` of tuples is created. Each tuple will store three values:
198+
- **Profit** (integer)
199+
- **Job ID** (integer)
200+
- **Deadline** (integer)
201+
202+
203+
#### 3. **Populating the Tuple Vector:**
204+
205+
```cpp
206+
for(int i = 0; i < id.size(); i++){
207+
v.push_back(make_tuple(profit[i], id[i], deadline[i]));
208+
}
209+
```
210+
211+
- A loop iterates over the input arrays (`id[]`, `profit[]`, `deadline[]`).
212+
- In each iteration, a tuple of `(profit, job id, deadline)` is created using `make_tuple` and added to the vector `v`.
213+
214+
**Example:**
215+
For input:
216+
- `id[] = {1, 2, 3}`
217+
- `deadline[] = {2, 1, 3}`
218+
- `profit[] = {20, 10, 40}`
219+
220+
The vector `v` will contain the following tuples:
221+
- `(20, 1, 2)`
222+
- `(10, 2, 1)`
223+
- `(40, 3, 3)`
224+
225+
226+
#### 4. **Sorting the Jobs by Profit in Descending Order:**
227+
228+
```cpp
229+
sort(v.begin(), v.end(), [](tuple<int, int, int>& a, tuple<int, int, int>& b){
230+
return get<0>(a) > get<0>(b);
231+
});
232+
```
233+
234+
- The jobs are sorted by profit in descending order using a custom comparison function.
235+
- `get<0>(a)` retrieves the profit of the job in tuple `a` (since it's the first element of the tuple).
236+
- Jobs with higher profits will come before jobs with lower profits.
237+
238+
**After Sorting (descending by profit):**
239+
- `(40, 3, 3)` → Job 3 with Profit 40
240+
- `(20, 1, 2)` → Job 1 with Profit 20
241+
- `(10, 2, 1)` → Job 2 with Profit 10
242+
243+
244+
#### 5. **Finding the Maximum Deadline:**
245+
246+
```cpp
247+
int maxiDeadline = INT_MIN;
248+
for(int i = 0; i < deadline.size(); i++){
249+
maxiDeadline = max(maxiDeadline, deadline[i]);
250+
}
251+
```
252+
253+
- A variable `maxiDeadline` is initialized to the smallest possible integer (`INT_MIN`).
254+
- A loop goes through all the deadlines and updates `maxiDeadline` to the largest value found in the `deadline[]` array.
255+
256+
**Example:**
257+
For input `deadline[] = {2, 1, 3}`, `maxiDeadline` will become `3` after the loop.
258+
259+
260+
#### 6. **Initializing the Schedule Array:**
261+
262+
```cpp
263+
vector<int> schedule(maxiDeadline + 1, -1);
264+
```
265+
266+
- A `schedule[]` array is created to keep track of the time slots.
267+
- The array size is `maxiDeadline + 1` to accommodate all time slots from `1` to `maxiDeadline`.
268+
- The array is initialized with `-1`, indicating that all time slots are initially empty.
269+
270+
**Example:**
271+
If `maxiDeadline = 3`, the `schedule[]` will look like this: `[-1, -1, -1, -1]`.
272+
273+
274+
#### 7. **Initializing Variables for Count and Profit:**
275+
276+
```cpp
277+
int count = 0;
278+
int maxProfit = 0;
279+
```
280+
281+
- `count` keeps track of the number of jobs successfully scheduled.
282+
- `maxProfit` stores the total profit earned from the scheduled jobs.
283+
284+
285+
#### 8. **Scheduling Jobs:**
286+
287+
```cpp
288+
for(int i = 0; i < v.size(); i++){
289+
int currProfit = get<0>(v[i]);
290+
int currJobId = get<1>(v[i]);
291+
int currDeadline = get<2>(v[i]);
292+
293+
for(int k = currDeadline; k > 0; k--){
294+
if(schedule[k] == -1){
295+
schedule[k] = currJobId;
296+
maxProfit += currProfit;
297+
count++;
298+
break;
299+
}
300+
}
301+
}
302+
```
303+
304+
- The algorithm then iterates through each job (from the sorted list of jobs):
305+
- Extract the job's **profit**, **job ID**, and **deadline**.
306+
- For each job, it tries to find the latest available time slot (starting from the job's deadline).
307+
- It checks if the time slot is free (i.e., `schedule[k] == -1`).
308+
- If an empty slot is found, it schedules the job, updates the `schedule[]` array with the job ID, increments the total profit (`maxProfit`), and increments the count of scheduled jobs (`count`).
309+
- The loop breaks after scheduling the job to move on to the next job.
310+
311+
**Example:**
312+
For sorted jobs:
313+
- **Job 3**: Deadline = 3, Profit = 40. It finds an empty slot at time 3 and schedules it.
314+
- **Job 1**: Deadline = 2, Profit = 20. It finds an empty slot at time 2 and schedules it.
315+
- **Job 2**: Deadline = 1, Profit = 10. But both slots before its deadline are occupied, so it can't be scheduled.
316+
317+
The `schedule[]` array will look like this: `[-1, -1, 1, 3]`.
318+
319+
320+
#### 9. **Returning the Result:**
321+
322+
```cpp
323+
return {count, maxProfit};
324+
```
325+
326+
- The function returns a vector containing:
327+
- `count`: The number of jobs scheduled.
328+
- `maxProfit`: The total profit earned from the scheduled jobs.
329+
330+
331+
### Example Walkthrough:
332+
333+
For the input:
334+
- `id[] = {1, 2, 3}`
335+
- `deadline[] = {2, 1, 3}`
336+
- `profit[] = {20, 10, 40}`
337+
338+
1. **After Sorting Jobs by Profit:**
339+
- `[(40, 3, 3), (20, 1, 2), (10, 2, 1)]`
340+
341+
2. **Find Maximum Deadline:** `maxiDeadline = 3`
342+
343+
3. **Initialize Schedule:** `[-1, -1, -1, -1]`
344+
345+
4. **Schedule Jobs:**
346+
- Job 3: Slot 3 → Schedule: `[-1, -1, -1, 3]`
347+
- Job 1: Slot 2 → Schedule: `[-1, -1, 1, 3]`
348+
- Job 2: Cannot be scheduled.
349+
350+
5. **Result:**
351+
- Number of jobs scheduled: `2`
352+
- Total profit: `40 + 20 = 60`
353+
354+
355+
### Time Complexity:
356+
357+
- Sorting the jobs by profit takes **O(n log n)**, where `n` is the number of jobs.
358+
- For each job, we may need to iterate through time slots up to its deadline. In the worst case, for each job, this takes **O(n)**.
359+
- Thus, the total time complexity is **O(n log n) + O(n^2)**, which simplifies to **O(n^2)**.
360+
361+
### Space Complexity:
362+
363+
- The `schedule[]` array takes **O(n)** space (to store time slots).
364+
- The vector `v` contains tuples, which also take **O(n)** space.
365+
- Thus, the overall space complexity is **O(n)**.

0 commit comments

Comments
 (0)