头条笔试题:任务调度 https://www.nowcoder.com/question/next?pid=8537279&qid=141057&tid=17430446
产品经理(PM)有很多好的idea,而这些idea需要程序员实现。现在有N个PM,在某个时间会想出一个 idea,每个 idea 有提出时间、所需时间和优先等级。对于一个PM来说,最想实现的idea首先考虑优先等级高的,相同的情况下优先所需时间最小的,还相同的情况下选择最早想出的,没有 PM 会在同一时刻提出两个 idea。
同时有M个程序员,每个程序员空闲的时候就会查看每个PM尚未执行并且最想完成的一个idea,然后从中挑选出所需时间最小的一个idea独立实现,如果所需时间相同则选择PM序号最小的。直到完成了idea才会重复上述操作。如果有多个同时处于空闲状态的程序员,那么他们会依次进行查看idea的操作。
求每个idea实现的时间。
输入第一行三个数N、M、P,分别表示有N个PM,M个程序员,P个idea。随后有P行,每行有4个数字,分别是PM序号、提出时间、优先等级和所需时间。输出P行,分别表示每个idea实现的时间点。
#include <bits/stdc++.h>
using namespace std;
#define M(a, b) memset(a,b,sizeof(a))
const int MAXN = 305;
typedef long long LL;
const int maxn = 3002;
int n, m, p;
struct Task {
int pm_index; // 产品所属pm
int raise_time; // 提出时间
int priority; // 优先级
int period; // 时长
int task_index; // 任务序号
int pm_task_index;
int end_time; // 终止时间
// bool operator < (const task& b) const{
// return raise_time <= b.raise_time;
// }
};
// sort according to the raise_time of task
struct compare_task {
bool operator()(const Task &a, const Task &b) {
return a.raise_time > b.raise_time; // 提出时间早的排在前面
}
};
struct compare_task_inner {
bool operator()(const Task &a, const Task &b) {
if (a.priority != b.priority) { // high priority first
return a.priority < b.priority;
} else {
if (a.period != b.period) { // short period first
return a.period > b.period;
} else {
return a.raise_time > b.raise_time; // early raise_time first
}
}
}
};
struct Manager {
priority_queue<Task, vector<Task>, compare_task> m_pq;
int most_desired_task(int start_time, Task &desired_task) {
priority_queue<Task, vector<Task>, compare_task_inner> cache_pq; // transfer
// while (!m_pq.empty()){
// auto temp = m_pq.top();
// m_pq.pop();
// printf("%d %d %d\n",temp.pm_index, temp.raise_time,temp.priority);
//
// }
while (!m_pq.empty() && m_pq.top().raise_time <= start_time) {
cache_pq.push(m_pq.top());
m_pq.pop();
}
// printf("m_pq.size():%d | cache_pq.size(): %d \n",m_pq.size(), cache_pq.size());
if (cache_pq.empty()) {
// no task's raise_time earlier than start_time
if (m_pq.empty()) {
return 0;
} else {
desired_task = m_pq.top();
m_pq.pop();
}
} else {
// choose the first task of cache_pq
desired_task = cache_pq.top();
cache_pq.pop();
}
while (!cache_pq.empty()) {
// transfer the remain tasks to m_pq
m_pq.push(cache_pq.top());
cache_pq.pop();
}
// printf("m_pq.size():%d | cache_pq.size(): %d \n",m_pq.size(), cache_pq.size());
return 1;
}
};
struct Programmer {
int next_work_time;
Programmer(int t) : next_work_time(t) {
}
};
int work_time;
int select_task(vector<Manager> &pms, Task &picked_task) {
auto cmp = [](const Task &a, const Task &b) {
if (a.raise_time == b.raise_time || (a.raise_time <= work_time && b.raise_time <= work_time)) {
// short period, first index
if (a.period != b.period) {
return a.period > b.period;
} else {
return a.pm_index > b.pm_index;
}
}
if (a.raise_time > work_time && b.raise_time > work_time) { // choose which raise first
return a.raise_time > b.raise_time;
}
if (a.raise_time > work_time) {
return true;
}
if (b.raise_time > work_time) {
return false;
}
return false;
};
priority_queue<Task, vector<Task>, decltype(cmp)> m_pq(cmp);
for (int i = 1; i <= n; i++) {
// printf("pm: %d\n",i);
// printf("pm.m_pq.size(): %d\n",pms[i].m_pq.size());
Manager& cur_manager = pms[i]; // 注意一定要引用,写成 Manager cur_manager = pms[i] 则会造成复制 pms[i] 给临时变量 cur_manager, 从而无法真正修改 pms[i] 的值
Task desired_task;
int ret = cur_manager.most_desired_task(work_time, desired_task);
if (ret == 1) {
m_pq.push(desired_task);
}
// printf("pm.m_pq.size(): %d\n",pms[i].m_pq.size());
}
if (m_pq.empty()) {
return 0;
}
picked_task = m_pq.top();
m_pq.pop();
// printf("%d")
// for(int i=1;i<=n;i++){
// printf("desired begins %d pms[i].m_pq.size(): %d\n",i,pms[i].m_pq.size());
// }
while (!m_pq.empty()) {
Task tmp = m_pq.top();
m_pq.pop();
pms[tmp.pm_index].m_pq.push(tmp); // restore
}
// for(int i=1;i<=n;i++){
// printf("desired finished %d pms[i].m_pq.size(): %d\n",i,pms[i].m_pq.size());
// }
return 1;
}
int a, b, c, d;
int main() {
cin >> n >> m >> p;
vector<Manager> pms(n + 1);
vector<Task> save_tasks(p + 1);
for (int i = 1; i <= p; i++) {
cin >> a >> b >> c >> d;
Task new_t;
new_t.pm_index = a;
new_t.raise_time = b;
new_t.priority = c;
new_t.period = d;
new_t.task_index = i;
pms[a].m_pq.push(new_t);
}
// for(int i=1;i<=n;i++){
// printf("pms[i].m_pq.size() %d\n",pms[i].m_pq.size());
// }
auto cmp = [](const Programmer &a, const Programmer &b) {
return a.next_work_time > b.next_work_time; // who finished first, first out
};
priority_queue<Programmer, vector<Programmer>, decltype(cmp)> losers_pq(cmp); // records the order of programmer
for (int i = 1; i <= m; i++) {
Programmer new_p(0);
losers_pq.push(new_p);
}
while (true) {
Programmer cur_p = losers_pq.top();
losers_pq.pop();
Task pt;
work_time = cur_p.next_work_time;
// for(int i=1;i<=n;i++){
// printf("select begins pms[i].m_pq.size() %d\n",pms[i].m_pq.size());
// }
int ret = select_task(pms, pt);
if (ret == 0) { // no task is picked, game over
break;
}
// for(int i=1;i<=n;i++){
// printf("select finished %d pms[i].m_pq.size(): %d\n",i,pms[i].m_pq.size());
// }
// printf("pt.raise_time %d, cur_p.next_work_time %d pt.period %d \n ",pt.raise_time,cur_p.next_work_time,pt.period);
pt.end_time = max(pt.raise_time, cur_p.next_work_time) + pt.period;
// printf("picked_task.end_time %d\n",pt.end_time);
save_tasks[pt.task_index] = pt; // 保存结果
cur_p.next_work_time = pt.end_time;
losers_pq.push(cur_p);
}
for (int i = 1; i <= p; i++) {
cout << save_tasks[i].end_time << endl;
}
return 0;
}