算法第二次作业-装配线分配问题

2024-01-20 05:10

本文主要是介绍算法第二次作业-装配线分配问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、运行环境:

Win7、Dev-C++

二、运行过程说明:

数据文件格式:

  • 第一行是线路1上的各个装配站装配的时间;
  • 第二行是线路2上的各个装配站装配的时间;
  • 第三行是线路1上的装配站到线路2的(下一个)装配站的运输时间;
  • 第四行是线路2上的装配站到线路1的(下一个)装配站的运输时间 ;
  • 第五行是底盘分别到线路1和线路2的第一个装配站所需要的时间;
  • 第六行是线路1和线路2的最后一个装配站分别到达终点的市时间。

输入格式:输入测试数据集文件编号。

 

输出:

 

三、算法设计

3.1问题描述:

装配一辆汽车,有两条装配线分别有n个装配点,每条装配线在进出所花时间为e[i],x[i] (i=0,1),每个装配点所需时间a[i][j](i=0,1;j=0,1,...,n-1),从一条装配线i的第j个装配点到另一条装配线的第j+1个装配点所需时间t[i][j]。

 

3.2解题思路:

DP算法的设计可以分为四个步骤:描述最优解的结构;递归定义最优解的值;按自底而上的方式计算最优解的值;由计算出的结果创造一个最优解。

用上面的四步来解题:

  • 描述最优解的结构,即通过工厂最快路线的结构。
  • 递归定义最优解的值,计算最快时间。
  • 按自底而上的方式计算最优解的值,即计算最快时间。
  • 由计算出的结果创造一个最优解,构造通过工厂的最快路线。

 

3.3数据结构的选择:

  • 假设两条装配线都有n个装配站;
  • 最短时间int型f_star;
  • 最后出口的线路选择l_star(因为求出口时,要有个统一的入口,根据f1[n]+x1和f2[n]+x2的大小决定L*为1还是为2);
  • 每个装配站的最短时间使用整型二维数组f[2][n];
  • 到达i线上的j站点来自于哪个线上的j-1,使用整型二维数组l[2][n](l[i][j],其中i=1或2,j表示第j个装配站);
  • 每个装配站的装配时间使用整型二维数组a[2][n];
  • 每个装配站的运输时间使用整型二维数组t[2][n];
  • 底盘分别到达装配线1和装配线2的运输时间使用一维整形数组int e[2];
  • 装配线1和装配线2的最后一个装配站分别到达目的地的运时用一维整形数组int x[2];

四、算法详细描述:

4.1步骤以及伪代码:

(1)描述最优解的结构,即通过工厂最快路线的结构。

最后的出口(1,n)从第(1,n-1)位置或(2,n-1)来,出口(2,n)类似。这样一次划分后,具有最优子结构:一个问题的最优解包含了子问题的一个最优解。题中找出通过装配站S(i,j)的最优解,包含了找出通过S(1,j-1)或S(2,j-1)的一个最优解,通过S(1,j)的最快路线只能是以下两种选择:

通过配件站S(1,j-1),然后直接到达S(1,j);

通过配件站S(2,j-1),然后从装配线2到装配线1,最后到达S(1,j)。

问题转化为了,为解决该问题(寻找通过任一条装配线上的j的最快路线),解决其子问题(寻找通过两条装配线上的j-1的最快路线)来构造问题最优解。

(2)递归定义最优解的值,计算最快时间。

第一步分析了最优解是如何拆分的,第二步就是用来组成最优解。根据题意,写出f(i)与f(i-1)之间的关系。

先不考虑边界情况,得到如下递归式:

 

然后处理边界性问题(入口和出口):

出口时,应该求解f1[n]+x1,f2[n]+x2。然后选出其中的最小值求解。

入口条件如下:

 

因此得到两个方程组和一个结果方程

 

(3)按自底而上的方式计算最优解的值,即计算最快时间。

动态规划问题,采用自底向上的方式,需要建立数组来保持,防止递归带来的时间消耗,因此数组保存的是要递归时的返回值。也就是递归表达式中的f1[n-1]以及f2[n-2]。将i从1àn增长,一步一步求解。

计算最快时间的伪代码如下:

FAST_WAY ( a, t, e, x, n)1   f1[1] ße1 + a1,12   f2[1] ße2 + a2,13   for jß2 to n4             do if f1[j-1] + a1,j <= f2[j-1] + t2,j-1 + a1,j5                      then f1[j] ß f1[j-1] + a1,j6                               l1[j] ß 17                      else f1[j] ß f2[j-1] + t2,j-1 + a1,j8                               l1[j] ß 29             do if f2[j-1] + a2,j <= f1[j-1] + t1,j-1 + a2,j10                    then f2[j] ß f2[j-1] + a2,j11                             l2[j] ß 212                    else f1[j] ß f1[j-1] + t1,j-1 + a2,j13                             l2[j] ß 114 if f1[n] + x1 <= f2[n] + x215           then f* ßf1[n] + x116                    l* ß117           else f* ß f2[n] + x2l* ß 2

(4)由计算出的结果创造一个最优解,构造通过工厂的最快路线。

如果只需要最优解的话,不需要这一步。但如果需要给出方案,就需要数组保存路径信息。

构造通过工厂的最快路线的伪代码如下:

PRINT_STATIONS ( l , l* , n ) :iß l*print “line” i “, station” nfor j ß li[j]do I <- li[j]print “line” i “,station” j-1

4.2代码:

#include <stdio.h>int f[2][6]={0};    //对应通过各个装配站的最短时间int l[2][6]={0};    //对应通过各个装配站的来源int l_star;//记录选择的线路int f_star;//记录到达最短时间,/***         Dp求解 最短时间**         二维数组a 存储没个装配站装配时间*         二维数组t 存储装配站间的运输时间*         一维数组a 存储底盘运输到线路1的时间  和  运输到线路2的时间*         一维数组x 存储线路1最后一站运输到目的地的时间是   和   线路2最后一站运输到目的地的时间是2;*         n 每个线路拥有的装配站数量**  !!!:计算时间的同时要保持线路的纪录**/void Fastest_Way(int a[][6],int t[][5],int e[],int x[],int n){int j=0;f[0][0] = e[0]+ a[0][0];f[1][0] = e[1]+ a[1][0];for (j=1;j<n;j++)                          //自底向上开始计算f[i][j]的值,与l[i][j]的值{//对于在线路1的装配站来说if (f[0][j-1]+a[0][j] <= f[1][j-1]+t[1][j-1]+a[0][j])//选择第一条线 过来的{f[0][j] = f[0][j-1]+a[0][j];           l[0][j] = 0;}else//选择从第二条线过来的{f[0][j] = f[1][j-1]+t[1][j-1]+a[0][j];l[0][j] = 1;}//对于在线路2的装配站来说if (f[1][j-1]+a[1][j] <= f[0][j-1]+t[0][j-1]+a[1][j])//选择从第二条线过来的{f[1][j] = f[1][j-1]+a[1][j];l[1][j] = 1;}else//选择从第一条线过来得{f[1][j] = f[0][j-1]+t[0][j-1]+a[1][j];l[1][j] = 0;}  }if (f[0][5] + x[0] <= f[1][5] + x[1]){f_star = f[0][5]+x[0];              //  f_star为通过装配线的最短时间  l_star为产品最后出自哪个生产线l_star = 0;}else{f_star = f[1][5]+x[1];l_star = 1;}printf("运输最短时间为:%d\n",f_star);}/***         根据记录得出最佳的路径 (根据站点顺序递归输出)*   *        二维数组l 记录了选择的线路l_star 和站点 n**/void Print_Station(int l[][6],int l_star,int n){  if ( n==0 )//边界条件return;l_star = l[l_star][n];/*递归*/Print_Station(l,l_star,n-1);printf("线路  %d ,  站点  %d\n",l[l_star][n]+1,n);}int main(){FILE *fp;/*用户输入文件序号*/int index;printf("请输入文件序号(1-6)!");scanf("%d",&index);if(index>=1&&index<=6){char fname[100];//sprintf(fname,"%s%d%s","input_assgin02_0",index,".dat");puts(fname);/*读取数据文件 FILE * fopen(char *filename, char *mode);*/if ((fp=fopen(fname,"r"))==NULL){printf("文件读取失败!");return -1;}}int a[2][6];           //装配时间int t[2][5];           //运输时间int e[2];                         //底盘运输到线路1、线路2的时间int x[2];                        //线路1、线路2最后一站运输到目的地的时间int i=0,j=0;/*对每个站点的装配时间赋值 */printf("每个站点的装配时间\n");for(i=0;i<2;i++){for(j=0;j<6;j++){fscanf(fp,"%d",&a[i][j]);printf("%d\t", a[i][j]);}putchar('\n');//每行结束换行}/*对站点两两之间的运输时间赋值*/printf("站点两两之间的运输时间\n");for(i=0;i<2;i++){for(j=0;j<5;j++){fscanf(fp,"%d",&t[i][j]);printf("%d\t", t[i][j]);}putchar('\n');//每行结束换行}/*底盘运输到线路1、线路2的时间*/printf("底盘运输到线路1和线路2的运输时间\n");for(i=0;i<2;i++){fscanf(fp,"%d",&e[i]);printf("%d\t", e[i]);}putchar('\n');/*终线路1、线路2最后一站运输到目的地的时间*/printf("线路1和线路2的最后一个装配站到目的地的运输时间\n");for(i=0;i<2;i++){fscanf(fp,"%d",&x[i]);printf("%d\t", x[i]);}putchar('\n');/*求解最短时间*/Fastest_Way(a,t,e,x,6);/*求解最佳线路*/printf("运输最佳线路为:\n");Print_Station(l,l_star,6);return 0;}

五、算法分析

动态规划由于从第二步开始每一步都利用上一步的结果来计算,从而避免了许多重复的计算,大大降低了时间复杂度。根据上面的工作方式,可以计算出时间复杂度为:O(n)。

空间复杂度:因为使用了二维数组、一维数组以及整型变量来保持记录,空间复杂度为:O(n)。

这篇关于算法第二次作业-装配线分配问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/624890

相关文章

MySQL的cpu使用率100%的问题排查流程

《MySQL的cpu使用率100%的问题排查流程》线上mysql服务器经常性出现cpu使用率100%的告警,因此本文整理一下排查该问题的常规流程,文中通过代码示例讲解的非常详细,对大家的学习或工作有一... 目录1. 确认CPU占用来源2. 实时分析mysql活动3. 分析慢查询与执行计划4. 检查索引与表

MySQL报错sql_mode=only_full_group_by的问题解决

《MySQL报错sql_mode=only_full_group_by的问题解决》本文主要介绍了MySQL报错sql_mode=only_full_group_by的问题解决,文中通过示例代码介绍的非... 目录报错信息DataGrip 报错还原Navicat 报错还原报错原因解决方案查看当前 sql mo

Spring Boot 整合 ShedLock 处理定时任务重复执行的问题小结

《SpringBoot整合ShedLock处理定时任务重复执行的问题小结》ShedLock是解决分布式系统中定时任务重复执行问题的Java库,通过在数据库中加锁,确保只有一个节点在指定时间执行... 目录前言什么是 ShedLock?ShedLock 的工作原理:定时任务重复执行China编程的问题使用 Shed

MYSQL事务死锁问题排查及解决方案

《MYSQL事务死锁问题排查及解决方案》:本文主要介绍Java服务报错日志的情况,并通过一系列排查和优化措施,最终发现并解决了服务假死的问题,文中通过代码介绍的非常详细,需要的朋友可以参考下... 目录问题现象推测 1 - 客户端无错误重试配置推测 2 - 客户端超时时间过短推测 3 - mysql 版本问

Git提交代码详细流程及问题总结

《Git提交代码详细流程及问题总结》:本文主要介绍Git的三大分区,分别是工作区、暂存区和版本库,并详细描述了提交、推送、拉取代码和合并分支的流程,文中通过代码介绍的非常详解,需要的朋友可以参考下... 目录1.git 三大分区2.Git提交、推送、拉取代码、合并分支详细流程3.问题总结4.git push

解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题

《解决IDEA使用springBoot创建项目,lombok标注实体类后编译无报错,但是运行时报错问题》文章详细描述了在使用lombok的@Data注解标注实体类时遇到编译无误但运行时报错的问题,分析... 目录问题分析问题解决方案步骤一步骤二步骤三总结问题使用lombok注解@Data标注实体类,编译时

大数据小内存排序问题如何巧妙解决

《大数据小内存排序问题如何巧妙解决》文章介绍了大数据小内存排序的三种方法:数据库排序、分治法和位图法,数据库排序简单但速度慢,对设备要求高;分治法高效但实现复杂;位图法可读性差,但存储空间受限... 目录三种方法:方法概要数据库排序(http://www.chinasem.cn对数据库设备要求较高)分治法(常

Vue项目中Element UI组件未注册的问题原因及解决方法

《Vue项目中ElementUI组件未注册的问题原因及解决方法》在Vue项目中使用ElementUI组件库时,开发者可能会遇到一些常见问题,例如组件未正确注册导致的警告或错误,本文将详细探讨这些问题... 目录引言一、问题背景1.1 错误信息分析1.2 问题原因二、解决方法2.1 全局引入 Element

关于@MapperScan和@ComponentScan的使用问题

《关于@MapperScan和@ComponentScan的使用问题》文章介绍了在使用`@MapperScan`和`@ComponentScan`时可能会遇到的包扫描冲突问题,并提供了解决方法,同时,... 目录@MapperScan和@ComponentScan的使用问题报错如下原因解决办法课外拓展总结@

MybatisGenerator文件生成不出对应文件的问题

《MybatisGenerator文件生成不出对应文件的问题》本文介绍了使用MybatisGenerator生成文件时遇到的问题及解决方法,主要步骤包括检查目标表是否存在、是否能连接到数据库、配置生成... 目录MyBATisGenerator 文件生成不出对应文件先在项目结构里引入“targetProje