AI刷题-多零件流水线优化问题
目录
问题描述
测试样例
解题思路:
问题理解
数据结构选择
算法步骤
代码实现:
1.创建数组标记每个零件的每个工序是否完成。
2.创建数组存储每个零件的工序数量。
3.创建数组存储每个零件的工序时间。
4.初始化
5.设置下标
6.创建优先队列
7.模拟整个零件加工
最终代码:
运行结果:
问题描述
小C、小U、小R是工厂里的三个工人,他们互相协同制作零件。零件的制作包括三种工序:"加工"、"质检"、"收尾",分别由小C、小U、小R负责。每个零件需要多次进行"加工"和"质检"工序,但只需要进行一次"收尾"工序。每次"加工"完成后,需要进行对应的"质检",只有当质检合格后,才可以开始下一次"加工"。当所有的"加工"和"质检"工序完成后,进行一次"收尾"工序,这样零件制作就算完成了。
小C、小U、小R的工作方式原本非常机械化,他们只能按照既定顺序一个工序一个工序地完成一个零件,比如对于一个零件的工序"加工1、质检1、加工2、质检2、收尾",他们会按顺序逐一完成各自的任务。
老板觉得这样太低效了,于是制定了新的加工方式:小C、小U、小R之间不应该互相等待,当他们因工序等待而被阻塞时,可以直接开始新零件的加工。但是每个工序在进行中不能被打断,必须连贯地完成。
例如,有5个零件,每个零件有7道工序,分别耗时如下:
零件一:10, 10, 10, 10, 10, 10, 20
零件二:10, 10, 10, 10, 10, 10, 20
零件三:10, 10, 10, 10, 10, 10, 20
零件四:10, 10, 10, 10, 10, 10, 20
零件五:10, 10, 10, 10, 10, 10, 20
(每一行的7个数字分别表示"加工1","质检1","加工2","质检2","加工3","质检3","收尾"的耗时)
假设零件按照5、4、3、2、1的优先级开始制作,优化后的工序流程中,小C、小U、小R会更加忙碌,避免空闲。
现在给你n个零件及每个零件的工序耗时,问在经过流程优化后,所有零件加工需要花费的总时间是多少?
测试样例
样例1:
输入:
n = 5, parts = [[7, 10, 10, 10, 10, 10, 10, 20], [7, 10, 10, 10, 10, 10, 10, 20], [7, 10, 10, 10, 10, 10, 10, 20], [7, 10, 10, 10, 10, 10, 10, 20], [7, 10, 10, 10, 10, 10, 10, 20]]
输出:200
样例2:
输入:
n = 3, parts = [[5, 10, 5, 10, 5, 10], [5, 2, 4, 6, 2, 10], [3, 10, 2, 5]]
输出:57
样例3:
输入:
n = 4, parts = [[5, 7, 5, 8, 5, 7], [3, 5, 2, 7], [5, 3, 6, 4, 3, 6], [7, 7, 3, 4, 7, 3, 5, 6]]
输出:60
解题思路:
问题理解
我们需要计算所有零件加工完成所需的总时间。每个零件的加工流程包括多个"加工"和"质检"工序,最后有一个"收尾"工序。小C、小U、小R可以并行工作,但每个工序必须连贯完成,不能被打断。
数据结构选择
- 零件列表:
std::vector<std::vector<int>> parts
,其中每个子向量表示一个零件的工序耗时。 - 时间记录:我们可以使用三个变量来记录小C、小U、小R的当前时间,分别表示他们完成当前工序的时间点。
算法步骤
- 初始化:初始化小C、小U、小R的当前时间为0。
- 遍历零件:按照优先级遍历每个零件。
- 处理每个零件的工序:
- 对于每个零件的每个工序(加工、质检、收尾),计算小C、小U、小R完成该工序的时间。
- 更新小C、小U、小R的当前时间,确保他们不会互相等待。
- 计算总时间:所有零件加工完成后,总时间即为小C、小U、小R中最后一个完成的时间。
代码实现:
1.创建数组标记每个零件的每个工序是否完成。
vector<vector<int>> flag(n, vector<int>(parts[0].size(), 0));
2.创建数组存储每个零件的工序数量。
vector<int> b(n);
3.创建数组存储每个零件的工序时间。
vector<vector<int>> a(n);
4.初始化
将parts里面的每一个工序的第一个零件放进对应的b数组里面,同时将第一个零件的时间都累加(已经加工了),然后把每一行的第二个到最后一个零件都放进a数组,最后标记flag数组的第一列的零件都为加工完成
for (int i = 0; i < n; ++i) {
b[i] = parts[i][0];
sum_jobs += b[i];
a[i] = vector<int>(parts[i].begin() + 1, parts[i].end());
flag[i][0] = 1;
}
5.设置下标
time
: 表示当前的时间点。m1
,m2
,m3
: 分别表示当前加工、质检和收尾工序的结束时间。last1i
,last1j
: 记录上一次加工工序的零件索引和工序索引。last2i
,last2j
: 记录上一次质检工序的零件索引和工序索引。last3i
: 记录上一次收尾工序的零件索引。
int time = 0;
int m1 = 0, m2 = 0, m3 = 0;
int last1i = -1, last1j = -1;
int last2i = -1, last2j = -1;
int last3i = -1;
6.创建优先队列
priority_queue<int, vector<int>, greater<int>> q;
q.push(0);
7.模拟整个零件加工
对于外循环:
q.top()
获取优先队列q
中的最小时间值(因为q
是一个最小堆)。q.pop()
移除这个最小时间值。
内循环:
q.top() == time
检查队列顶部的下一个任务是否与当前时间time
相同。q.pop()
移除这个任务。
while (sum_jobs > 0) {
time = q.top();
q.pop();
while (!q.empty() && q.top() == time) {
q.pop();
}
if (time == m3 && last3i != -1) {
sum_jobs -= 1;
}
if (time == m2 && last2i != -1 && last2j != -1) {
flag[last2i][last2j + 1] = 1;
sum_jobs -= 1;
}
if (time >= m1) {
if (time == m1 && last1i != -1 && last1j != -1) {
flag[last1i][last1j + 1] = 1;
sum_jobs -= 1;
}
// Get suitable m1
bool found = false;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < b[i]; j += 2) {
if (flag[i][j] == 1 && j != b[i] - 1) {
int temi = i, temj = j;
flag[temi][temj] = 0;
m1 = time + a[temi][temj];
last1i = temi;
last1j = temj;
q.push(m1);
found = true;
break;
}
}
if (found) break;
}
}
if (time >= m2) {
// Get suitable m2
bool found = false;
for (int i = 0; i < n; ++i) {
for (int j = 1; j < b[i]; j += 2) {
if (flag[i][j] == 1) {
int temi = i, temj = j;
flag[temi][temj] = 0;
m2 = time + a[temi][temj];
last2i = temi;
last2j = temj;
q.push(m2);
found = true;
break;
}
}
if (found) break;
}
}
if (time >= m3) {
// Get suitable m3
for (int i = 0; i < n; ++i) {
if (flag[i][b[i] - 1] == 1) {
int temi = i;
flag[temi][b[temi] - 1] = 0;
m3 = time + a[temi][b[temi] - 1];
last3i = temi;
q.push(m3);
break;
}
}
}
}
最终代码:
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
int solution(int n, vector<vector<int>> parts) {
vector<vector<int>> flag(n, vector<int>(parts[0].size()+10, 0));//标记每个零件的每个工序是否完成
vector<int> b(n,0);//保存每个零件的工序数量
int sum_jobs = 0;
vector<vector<int>> a(n);//存储每个零件的工序时间
for (int i = 0; i < n; ++i) {
b[i] = parts[i][0];
sum_jobs += b[i];
a[i] = vector<int>(parts[i].begin() + 1, parts[i].end());
flag[i][0] = 1;
}
int time = 0;
int m1 = 0, m2 = 0, m3 = 0;
int last1i = -1, last1j = -1;
int last2i = -1, last2j = -1;
int last3i = -1;
priority_queue<int, vector<int>, greater<int>> q;
q.push(0);
while (sum_jobs > 0) {
time = q.top();
q.pop();
while (!q.empty() && q.top() == time) {
q.pop();
}
if (time == m3 && last3i != -1) {
sum_jobs -= 1;
}
if (time == m2 && last2i != -1 && last2j != -1) {
flag[last2i][last2j + 1] = 1;
sum_jobs -= 1;
}
if (time >= m1) {
if (time == m1 && last1i != -1 && last1j != -1) {
flag[last1i][last1j + 1] = 1;
sum_jobs -= 1;
}
// Get suitable m1
bool found = false;
for (int i = 0; i < n; ++i) {
for (int j = 0; j < b[i]; j += 2) {
if (flag[i][j] == 1 && j != b[i] - 1) {
int temi = i, temj = j;
flag[temi][temj] = 0;
m1 = time + a[temi][temj];
last1i = temi;
last1j = temj;
q.push(m1);
found = true;
break;
}
}
if (found) break;
}
}
if (time >= m2) {
// Get suitable m2
bool found = false;
for (int i = 0; i < n; ++i) {
for (int j = 1; j < b[i]; j += 2) {
if (flag[i][j] == 1) {
int temi = i, temj = j;
flag[temi][temj] = 0;
m2 = time + a[temi][temj];
last2i = temi;
last2j = temj;
q.push(m2);
found = true;
break;
}
}
if (found) break;
}
}
if (time >= m3) {
// Get suitable m3
for (int i = 0; i < n; ++i) {
if (flag[i][b[i] - 1] == 1) {
int temi = i;
flag[temi][b[temi] - 1] = 0;
m3 = time + a[temi][b[temi] - 1];
last3i = temi;
q.push(m3);
break;
}
}
}
}
return time;
}
int main() {
vector<vector<int>> parts1 = {{7, 10, 10, 10, 10, 10, 10, 20},
{7, 10, 10, 10, 10, 10, 10, 20},
{7, 10, 10, 10, 10, 10, 10, 20},
{7, 10, 10, 10, 10, 10, 10, 20},
{7, 10, 10, 10, 10, 10, 10, 20}};
vector<vector<int>> parts2 = {{5, 10, 5, 10, 5, 10},
{5, 2, 4, 6, 2, 10},
{3, 10, 2, 5}};
vector<vector<int>> parts3 = {{5,7,5,8,5,7},{3,5,2,7},{5,3,6,4,3,6},{7,7,3,4,7,3,5,6}};
cout << (solution(5, parts1) == 200) << endl;
cout << (solution(3, parts2) == 57) << endl;
cout << (solution(4, parts3) == 60) << endl;
return 0;
}
运行结果: