Job Scheduler
// 上机,Job Scheduler。每一行输入是这样:
// J1:Job号;
// 0023, 24小时制的开始时间 00:23;
// 45:Job需要45分钟。
// 输出Job和对应的Machine No.(!!并且,如果同时有多个machine 空闲,要用编号小的那个!!)
// input
// J1 0023 45
// J2 0025 10
// J3 0100 60
// output
// J1 M1
// J2 M2
// J3 M1
// Qs:
// 1. Any duplicate jobs from input?
// 2. If the previous job end
// Do we have cases for overnight jobs? where it starts with 23:20 for example and last 50 minutes.
// it's hard to justify the end time with other jobs to figure out which one finished first?
#include <vector>
#include <queue>
#include <string>
#include <iostream>
#include <sstream>
using namespace std;
// Convert to number of minutes since midnight?
int parseTime(const string& timeStr) {
int hour = stoi(timeStr.substr(0, 2));
int minute = stoi(timeStr.substr(2, 2));
return hour * 60 + minute;
}
class Machine {
public:
Machine(int i) {
idx = i;
endTime = 0;
};
int idx;
int endTime;
string getName() {
return "M" + to_string(this->idx);
}
void debug() {
cout << getName() << " endTime: " << endTime << endl;
}
};
class Job {
public:
Job(string id, string startTime, string duration) {
jobId = id;
start = parseTime(startTime);
end = start + stoi(duration);
}
string jobId;
int start;
int end;
};
// Intuition, we loop through each job,
// for each job we find if there are any idle machine that can handle it, initially we only have one machine.
//
// Whenever there is no idle machine, we check if ocupied machine has finished?
// N be the number of machines.
// M be the number of jobs.
// Sorting jobs takes O(M*LogM)
// Popping and pushing into PQ each cost O(logN) with for loop over jobs: O(M*LogN)
// Time: O(mlogm + mlogn), Space: O(n + logn for sort in c++)
unordered_map<string, string> jobScheduler(vector<Job>& jobs) {
if (jobs.empty()) {
return {};
}
sort(jobs.begin(), jobs.end(), [](const Job& j1, Job& j2) {
return j1.start < j2.start;
});
auto occupiedMachineCmp = [](Machine a, Machine b) {
if (a.endTime == b.endTime) {
return a.idx > b.idx;
}
return a.endTime > b.endTime;
};
auto idleMachineCmp = [](Machine a, Machine b) {
return a.idx > b.idx;
};
priority_queue<Machine, vector<Machine>, decltype(occupiedMachineCmp)> occupiedMachinePQ(occupiedMachineCmp);
priority_queue<Machine, vector<Machine>, decltype(idleMachineCmp)> idleMachinePQ(idleMachineCmp);
// The first idle machine.
Machine m1 = Machine(1);
idleMachinePQ.push(m1);
int n = jobs.size();
int counter = 2; // new machine will start with number 2.
unordered_map<string, string> assignments;
for (int i = 0; i < n; i++) {
string jobId = jobs[i].jobId;
int jobStartTime = jobs[i].start;
int jobEndTime = jobs[i].end;
// if (!occupiedMachinePQ.empty()) {
// Machine m = occupiedMachinePQ.top();
// m.debug();
// }
// cout << "curr job start time: " << jobStartTime << endl;
// Move machine from occupied machine to idle machine if previous job already ended.
while (!occupiedMachinePQ.empty() && occupiedMachinePQ.top().endTime <= jobStartTime) {
Machine curr = occupiedMachinePQ.top();
occupiedMachinePQ.pop();
idleMachinePQ.push(curr);
}
// If we have idle machine, use it.
if (idleMachinePQ.size() > 0) {
Machine curr = idleMachinePQ.top();
idleMachinePQ.pop();
curr.endTime = jobEndTime;
occupiedMachinePQ.push(curr);
assignments[jobId] = curr.getName();
} else {
Machine newMachine = Machine(counter++);
newMachine.endTime = jobEndTime;
occupiedMachinePQ.push(newMachine);
assignments[jobId] = newMachine.getName();
}
}
return assignments;
}
vector<Job> parseStdin() {
vector<Job> res;
string line;
while (getline(cin, line)) {
string jobId, startTime, endTime;
istringstream iss(line);
iss >> jobId >> startTime >> endTime;
Job j = Job(jobId, startTime, endTime);
res.push_back(j);
}
return res;
}
// J1 0023 45
// J2 0025 10
// J3 0100 60
// J4 0108 20
// J5 0201 30
// J6 0112 30
// job: J4 get assigned to M1
// job : J6 get assigned to M3
// job : J3 get assigned to M2
// job : J2 get assigned to M2
// job : J5 get assigned to M1
// job : J1 get assigned to M1
int main() {
vector<Job> jobs = parseStdin();
unordered_map<string, string> res = jobScheduler(jobs);
for (auto i : res) {
cout << "job: " << i.first << " get assigned to " << i.second << endl;
}
return 0;
}```
Last updated