dp经典问题:装配线调度

dp经典问题:装配线调度

装配线调度问题(Assembly Line Scheduling Problem) 是一个经典的动态规划问题。这个问题的目标是通过在两条装配线上调度任务,来最小化完成整个装配过程所需的总时间。


问题描述

假设有两条装配线,每条装配线上有𝑛个工作站。每个工作站都需要一定的时间来处理其任务:

a 1 [ i ] ← 第一条装配线处理第 i 个任务所需要的时间 a_1[i] \gets 第一条装配线处理第 i 个任务所需要的时间 a1[i]第一条装配线处理第i个任务所需要的时间
a 2 [ i ] ← 第二条装配线处理第 i 个任务所需要的时间 a_2[i] \gets 第二条装配线处理第 i 个任务所需要的时间 a2[i]第二条装配线处理第i个任务所需要的时间

此外,从一个装配线切换到另一装配线是需要时间的

t 1 [ i ] ← 装配线 1 切换到装配线 2 并到达第 i 个工作站的时间。 t_1[i] \gets 装配线 1 切换到装配线 2 并到达第 i 个工作站的时间。 t1[i]装配线1切换到装配线2并到达第i个工作站的时间。
t 2 [ i ] ← 装配线 2 切换到装配线 1 并到达第 i 个工作站的时间。 t_2[i] \gets 装配线 2 切换到装配线 1 并到达第 i 个工作站的时间。 t2[i]装配线2切换到装配线1并到达第i个工作站的时间。

最初进入装配线的时间

e 1 ← 表示进入装配线 1 的时间。 e_1 \gets 表示进入装配线 1 的时间。 e1表示进入装配线1的时间。

e 2 ← 表示进入装配线 2 的时间。 e_2 \gets 表示进入装配线 2 的时间。 e2表示进入装配线2的时间。

离开装配线的时间

x 1 ← 表示离开装配线 1 的时间 x_1 \gets 表示离开装配线1的时间 x1表示离开装配线1的时间

x 2 ← 表示离开装配线 2 的时间 x_2 \gets 表示离开装配线2的时间 x2表示离开装配线2的时间

问题分析

Step1:识别状态

T i [ j ] ← 到达第 i 条装配线上第 j 个工作站的最短时间 T_i[j] \gets 到达第 i 条装配线上第j个工作站的最短时间 Ti[j]到达第i条装配线上第j个工作站的最短时间

Step2:给出边界条件

最初进入装配线的时间为
T 1 [ 0 ] = e 1 + a 1 [ 0 ] T_1[0] = e_1+a_1[0] T1[0]=e1+a1[0]
T 2 [ 0 ] = e 2 + a 2 [ 0 ] T_2[0] = e_2+a_2[0] T2[0]=e2+a2[0]

Step3:写出状态转移方程

为了从一个工作站转移到下一个工作站,我们有两种选择:继续在当前装配线上,或者切换到另一条装配线。每次都是从最优子问题解的状态转移到当前状态,具体的状态转移方程如下:

T 1 [ i ] = m i n ( T 1 [ i − 1 ] + a 1 [ i ] , T 2 [ i − 1 ] + a 1 [ i ] + t 2 [ i ] ) T_1[i] = min(T1[i-1]+a_1[i],T2[i-1]+a_1[i]+t_2[i]) T1[i]=min(T1[i1]+a1[i],T2[i1]+a1[i]+t2[i])
T 2 [ i ] = m i n ( T 2 [ i − 1 ] + a 2 [ i ] , T 1 [ i − 1 ] + a 2 [ i ] + t 1 [ i ] ) T_2[i] = min(T2[i-1]+a_2[i],T1[i-1]+a_2[i]+t_1[i]) T2[i]=min(T2[i1]+a2[i],T1[i1]+a2[i]+t1[i])

Step3:递推最终状态

从进入装配线开始进行递推,每一次的状态都是最优子问题解,最终构成了最优结构。

T n = m i n ( T 1 [ n − 1 ] + x 1 , T 2 [ n − 1 ] + x 2 ) T_n=min(T_1[n-1]+x1,T_2[n-1]+x2) Tn=min(T1[n1]+x1,T2[n1]+x2)

#include<iostream>
#include<vector>

using namespace std;

int assembly(vector<int>&a1,vector<int>&a2,vector<int>&t1,vector<int>&t2,int e1,int e2,int x1,int x2,int n){
    vector<int>T1(n);
    vector<int>T2(n);
    T1[0]=e1+a1[0];
    T2[0]=e2+a2[0];
    for(int i=1;i<n;i++){
        T1[i]=min(T1[i-1]+a1[i],T2[i-1]+a2[i]+t2[i]);
        T2[i]=min(T2[i-1]+a2[i],T1[i-1]+a1[i]+t1[i]);
    }
    return min(T1[n-1]+x1,T2[n-1]+x2);
}

int main() {
    vector<int> a1 = {4, 5, 3, 2};
    vector<int> a2 = {2, 10, 1, 4};
    vector<int> t1 = {0, 7, 4, 5};
    vector<int> t2 = {0, 9, 2, 8};
    int e1 = 10, e2 = 12, x1 = 18, x2 = 7;
    int n = a1.size();
    
    cout << "Minimum cost: " << assembly(a1, a2, t1, t2, e1, e2, x1, x2, n) << endl;

    return 0;
}
动态规划是一种优化算法,常用于解决装配线调度问题这类涉及最优化决策的问题装配线调度通常涉及到如何安排工人的工作顺序和任务分配,以最大化效率,比如最小化生产周期或总等待时间。 **问题描述**: 装配线调度问题的目标是找到一种最优的工作流程安排,使得整个生产线上的任务能按顺序完成,并尽可能减少等待时间和机器闲置时间。每个任务都有一定的处理时间,工人需要按照特定顺序操作,而且有些任务之间可能存在依赖关系。 **输入**: - 一组任务,每个任务有执行时间(表示完成该任务所需的时间)。 - 每个任务的优先级或依赖关系(例如,某些任务必须在另一些任务完成后才能开始)。 - 工人数目及其工作效率信息。 **输出**: - 最优的任务执行序列,即工人们如何在最小化总时间的情况下完成所有任务。 - 最小化的总执行时间(生产周期)。 **解题思路(伪代码)**: ```python function dynamicProgramming(tasks, dependencies, workers): n = number_of_tasks dp = [[0] * n for _ in range(n)] # 初始化二维数组,dp[i][j]代表第i个任务到第j个任务的最短完成时间 prev_task = [-1] * n # 记录每个任务前一个可以依赖的任务 for i in range(1, n): # 遍历任务从第二个开始 for j in range(i, n): for k in range(j): # 查找可行的工作顺序 if dependencies[k] == i and tasks[j] <= tasks[k]: # 如果满足依赖条件 dp[i][j] = min(dp[i][j], dp[k][j] + tasks[j]) # 更新最优完成时间 prev_task[j] = k # 更新任务的前一个任务 best_sequence = [] # 最佳任务执行顺序 current_task = n - 1 # 从最后一个任务开始回溯 while current_task >= 0: best_sequence.append(current_task) current_task = prev_task[current_task] return best_sequence, dp[n-1][0] # 返回最佳执行顺序和总执行时间 ``` **时间复杂度**: 由于这是一个完全填充的二维动态规划表,对于`n`个任务,我们需要填写一个大小为`n x n`的表格,查找依赖关系的嵌套循环复杂度为O(n^3)。但实际上,在实际应用中,通过剪枝等技巧,这个问题通常可以在接近线性的O(n^2)时间内解决。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我我我想出去玩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值