装配线问题
装配线问题:
韩鸡鸡一直强调的装配线问题其实很简单,也算是动态规划里面比较简单的问题了。
在上面的图中,我们可以看到也就是一个车间有两条装配线,每一个相对位置的功能是相同的。。如图中a11和a21,它们的功能是相同的,
都是装配一个零件,但是它们所需的时间却不相同。而且不同装配线间的移动是要花时间的。但是在同一条装配线上移动是不需要花时间的
,当然了,我们只能从左往右依次装配零件。那么问题来了,怎么样选择装配路线使得时间最少?当然每件装配线都有它的进入时间和移出
时间,这个就不多说了。
那么对于这个问题的解,我们还是可以采用典型的动态规划的问题解法,装原问题划分为子问题,找到原问题与子问题的关系,然后子问题
再划分为子问题了。
那么对于这个问题,原问题是我们在离开装配线1和2时,所花时间最少。当然我们可以有多种离开的方法,从装配线1离开或者2离开,我们
暂且不考虑离开的时间x1和x2.
假设是从装配线1离开,离开最后的点a1n 所花的时间为Sn,它花的时间假设是最少的,于是那么这个问题的子问题是会么呢?
那么Sn和Sn-1有何联系呢,对于Sn的到达,其实有两条中径可以选第一条呢,就是通过a1n-1,第二条呢,就是通过从装配线2过来嘛,也就是a2n-1
于是问题来了,Sn和它们有什么关系呢,其实关系是有的。也就是我们的Sn肯定那两条选择的路径中所花时间最少的那条了,也就是
就是算法导论(第二版)中间的原话了。
我们可以看到其中还有一个f2,以及一个f1,那么,它们有什么关系呢?
其实f1和f2的引入是为了假设我们不知道最后是从第一条装配线出来还是从第二条装配线出来,那么我们就可以假设了,两者都要假设,然
后求两者的最小值,就可以了,而且求这两条装配线并不是独立的,而是它们间相互有关系。
你们看,我们的f1[j]是括号里面两者的较小值,也就是两条路径中选择时间最少的。这当然是肯定的。那么其中涉及到的f1[j-1]和f2[j-1]呢,那么
它们肯定也是在它们的情况选择两条可以到达它们路径中的较小值啊。。有点像“贪心算法”的问题,也就是每次总是选择是好的那种情况了。
刚刚我们是反着来,那么正着来呢,也就是从左边开始,往右边走,还是由
同理:
我们总是选择最好的那条路线。
#ifndef ASSEMBLE_LINE_H
#define ASSEMBLE_LINE_H
#include<iostream>
#include<string>
class AssembleLine{
private:
int AssOneIn; //第一条装配线输入的代价
int AssTwoIn; //第二条装配线输入的代价
int AssOneOut; //第一条装配线输出的代价
int AssTwoOut; //第二条装配线输出的代价
int *Ass_one; //第一条装配线零件装配代价
int Len_one; //第一条装配线的长度
int *Ass_two; //第二条装配线零件的装配代价
int Len_two; //第二条装配线的长度
int *AssOneToTwo; //第一条装配线转入第二条的代价
int *AssTwoToOne; //第二条装配线转入第一条的代价
int *f1; //记录第一条装配线
int *f2; //记录第二条装配线
public:
AssembleLine(int *&ass1,int len1,int *&ass2,int len2):Ass_one(ass1),Ass_two(ass2),Len_one(len1),Len_two(len2){
}
int assembleMin();
};
#include"AssembleLine.h"
#define Min(a,b) a<b? a:b
int AssembleLine::assembleMin(){
f1[0]=this->AssOneIn+this->Ass_one[0];
f2[0]=this->AssTwoIn+this->Ass_two[0];
for(int i=1;i<this->Len_one; i++){
f1[i]=Min((f1[i-1]+this->Ass_one[i]),(f2[i-1]+this->Ass_one[i]+this->AssTwoToOne[i-1]));
f2[i]=Min((f2[i-1]+this->Ass_two[i]),(f2[i-1]+this->Ass_two[i]+this->AssOneToTwo[i-1]));
}
return Min((f1[this->Len_one-1]+this->AssOneOut),(f2[this->Len_two-1]+this->AssTwoOut));
}