动态规划解决装配线调度问题


参考书籍:算法导论

问题描述:

共有两条装配线,每条有n个装配站,装配线i的第j个装配站用S[i,j]表示,    该站的装配时间用a[i,j]表示,一个汽车底盘进入装配线i,花费时间为e1,如果通过一条线的第j个装配站,这个底盘来到任意一条的第j+1个装配站,如果是相同的装配站,则没有额外的时间开销,如果移动到了另外一条装配线上,则花费时间t[i,j]。在离开一条装配线的第n个装配站后,完成汽车花费时间为xi离开工厂。待求解的问题是:应该分别在装配线1,2中选择哪些装配站,才能使汽车通过工厂的总时间最小。

装配站示意图:


分析过程:

动态规划的第一个步骤是描述最优子结构的特征。对于装配线调度问题,例:对于第一条装配线上的任意一个装配站S[1,j],到该装配站的最小时间可以看作为:从装配站S[1,j-1]出发到达S[1,j],或者通过S[2,j-1]出发加上额外时间t[2,j-1]到达S[1,j]。这里,S[1,j-1]和S[2,j-1]之前必定是利用了最短的时间到达了这两个装配站。这时就可以把问题转换为求出到达S[1,j-1]和S[2,j-1]的最短时间是多少,以此类推。

利用子问题的最优解来递归出一个最优解的值。用fi[j]表示一个底盘由起点到S[i,j]装配站的最短时间,最终通过工厂的总最小时间为f*;

f* = min(f1[n]+x1,f2[n]+x2);

对于f1[1]和f2[1]有:

f1[1] = e1 + a[1,1];

f2[1] = e2 + a[2,1];

         对于f1[j]和f2[j],j>1,有:

                   f1[j] = min(f1[j-1] + a[1,j], f2[j-1] + t[2,j-1] + a[1,j])

                   f2[j] = min(f2[j-1] + a[2,j] ,f1[j-1] + t[1,j-1] + a[2,j])

         以上两个式子反应了到达装配站S[i,j]的两种选择,取这两者较小者赋值给fi[j].

         为了跟踪最优解的构造过程,特引入li[j];为装配线的编号,例如:l1[3]=2,含义是:到达装配站S[1,3]的上一条装配线是2号装配线。

         以下为整个构造过程:


通过工厂的最快时间的路线:

 

l  C++代码实现如下:

#include<iostream>

using namespace std;

 

int printStation(int *l1,int *l2,int resultI,int n){

         cout<<"line"<<resultI<<" station "<<n<<endl;

         int tempI= resultI;

         for(inti=n-2;i>=0;i--){

                   if(tempI ==1){

                            cout<<"line"<<*(l1+i)<<" station "<<i+1<<endl;

                            tempI= *(l1+i);

                   }elseif(tempI == 2){

                            cout<<"line"<<*(l2+i)<<" station "<<i+1<<endl;

                          tempI= *(l2+i);

                   }

         }

}

 

int getSelected(int *line_1,int *line_2    ,int *time_1,int *time_2){

         int f1[6],f2[6];

         int l1[5],l2[5];

         f1[0] = *time_1 +*line_1 ;

         f2[0] = *time_2 +*line_2 ;

         int i=1;

         for(;i<6;i++){

                   if((f1[i-1])<=(f2[i-1]+*(time_2 + i))){

                            f1[i]= f1[i-1] + *(line_1 + i);

                            l1[i-1]= 1;

                   }else{

                            f1[i]= f2[i-1]+ *(time_2 + i)+*(line_1 + i);

                            l1[i-1]= 2;

                   }

                   if((f2[i-1]+*(line_2+i))<=(f1[i-1]+*(time_1        +i) + *(line_2+i))){

                            f2[i]= f2[i-1]+*(line_2+i);

                            l2[i-1]= 2;

                   }else{

                            f2[i]= f1[i-1]+*(time_1 + i) + *(line_2+i);

                            l2[i-1]= 1;

                   }

         }

         int result;

         int resultI;

         if((f1[i-1] +*(time_1+i)) < (f2[i-1]+*(time_2     +i))){

                   result =f1[i-1] + *(time_1+i);

                   resultI = 1;

         }else{

                   result =f2[i-1]+ *(time_2+i);

                   resultI = 2;

         }

         printStation(l1,l2,resultI,i);

         return 1;

        

}

 

int main(){

         int line_1[6] ={7,9,3,4,8,4};

         int line_2[6] ={8,5,6,4,5,7};

         int time_1[7] ={2,2,3,1,3,4,3};

         int time_2[7] ={4,2,1,2,2,1,2};

         getSelected(line_1,line_2,time_1,time_2);

         return 1;

}



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值