流水线问题(算法设计)C++

目录

一、需求分析

[1.1 问题描述](#1.1 问题描述)

[1.2 数据需求](#1.2 数据需求)

[1.3 功能需求](#1.3 功能需求)

[1.4 开发环境](#1.4 开发环境)

二、概要设计

[2.1 抽象数据类型 ADT 的定义](#2.1 抽象数据类型 ADT 的定义)

[2.2 系统的主要功能模块](#2.2 系统的主要功能模块)

[2.3 功能模块联系图](#2.3 功能模块联系图)

三、详细设计

[3.1 数据结构设计](#3.1 数据结构设计)

[3.2 主要算法](#3.2 主要算法)

四、系统运行及结果分析

[1. 用户界面](#1. 用户界面)

[2. 程序运行样例](#2. 程序运行样例)

[3. 程序结果分析](#3. 程序结果分析)

五、总结与思考


一、需求分析

1.1 问题描述

某工厂生产的产品需历经 3 道工序,为提升效率,需确定加工顺序,以实现生产 n 件产品的总时长最短。每件产品的各工序耗时各异。要求输入 n(n≥10),并递增 n 至少给出 3 组运行数据,对比程序运行时间。设计程序接收订单信息及工序时长,据此计算最短生产时间,即完成所有产品所需的最小时间。程序核心任务是依据输入优化工序安排,使总生产时间最小化。

1.2 数据需求

  1. 输入:订单信息:接收产品数量 n,代表工厂要生产的产品总数。
  1. 输入:工序时长信息:以二维矩阵或数组呈现,行对应产品,列对应工序,元素表示相应工序的时长。

1.3 功能需求

  1. 错误情况处理:输入订单及工序时长后,判断输入是否无效。若出现无效产品数量、负数工序时长等错误输入,进行错误提示或异常处理。
  1. 优化加工时长:运用分支限界法,根据输入的产品数量及各产品工序耗时,计算生产 n 件产品的最小总时长。
  1. 确定输出:依据输入,程序返回最小总时长,即完成 n 件产品所需的最短时间。
  1. 确定最优加工顺序:借助动态规划算法结果,确定使总时长最小的工序顺序。

1.4 开发环境

采用 Code::Blocks 作为开发环境,它是用于 C 和 C++ 等编程语言的集成开发环境(IDE),支持多种编译器,具备强大调试功能,可在开发中定位代码错误,还能将相关文件组织于项目中,便于代码管理、版本控制与共享,提高开发效率。

二、概要设计

2.1 抽象数据类型 ADT 的定义

ADT 结构体

    • 数据对象:包含多种类型数据项,如变量、数组、指针等。
    • 数据关系:数据项间存在相关性。
    • 基本操作
      • 创建:使用 typedef struct Node 创建新结构体对象。
      • 访问:通过结构体对象和成员名访问成员。
      • 赋值:将一个结构体对象赋值给当前对象。
      • 修改:修改结构体中成员的值。

ADT info

    • 数据对象:信息记录,含整型成员和数组成员。
    • 数据关系:无特定关系描述。
    • 基本操作:无特定操作描述。

ADT 线性表

    • 数据对象:相同数据类型数据元素的集合。
    • 数据关系:数据元素间有前驱后继关系。
    • 基本操作
      • 创建:构造空顺序表 L。
      • 插入:向线性表 L 中插入元素 e。
      • 删除:获取并删除线性表 L 的首个元素。

ADT 堆

    • 数据对象:包含元素实际数据及在堆中的位置信息。
    • 数据关系:对于非叶子节点 i,满足 data [i] >= data [2 * i + 1] 和 data [i] >= data [2 * i + 2](或 data [i] <= data [2 * i + 1] 和 data [i] <= data [2 * i + 2]);对于节点 i 和 j,当 i 是 j 的祖先节点时,data [j] <= data [i](或 data [j] >= data [i])。
    • 初始条件:给定顺序表 L,起始位置 s 和结束位置 m。
    • 操作结果:在给定范围内对顺序表 L 进行操作。

2.2 系统的主要功能模块

  1. inlIst 函数:初始化顺序表 L 为空。
  2. linsert 函数:向顺序表 L 插入元素。
  3. GetElem 函数:获取并删除顺序表 L 的首个元素。
  4. heaps 函数:实现堆排序中的堆调整操作。
  5. Creat 函数:构建大根堆。
  6. Sort 函数:对数组进行堆排序。
  7. Min1 函数:计算指定节点 k 与其他节点权重的最小值。
  8. Min2 函数:计算指定节点 k 与其他节点路径权重之和的最小值。
  9. fenzhi 函数:使用分支限界法求解最优路径问题。
  10. main 函数:程序入口,接收用户输入产品数量和加工时间,调用 fenzhi 函数求解最优路径。
  11. 异常处理模块:判断输入是否无效,对无效输入(如无效产品数量、负数工序时长)进行错误处理并给出提示。

2.3 功能模块联系图

三、详细设计

3.1 数据结构设计

  1. 结构体
cpp 复制代码
typedef struct {

int x;

int Lw[100] = {0};

int M[100] = {0};

int g;

} info;

线性表

cpp 复制代码
typedef struct {

info data[MAXSIZE];

int length;

} Sqlist;

cpp 复制代码
void heaps(Sqlist &L, int s, int m) { //堆的创建

int j;

info rc;

memcpy(&rc, &L.data[s], sizeof(info));

for (j = 2 * s; j <= m; j = j * 2) {

if (j < m && L.data[j].x < L.data[j + 1].x)

++j;

if (rc.x >= L.data[j].x)

break;

memcpy(&L.data[s], &L.data[j], sizeof(info));

s = j;

}

memcpy(&L.data[s], &rc, sizeof(info));

}

void Creat(Sqlist &L) { //对堆进行创建和调整

int n, i;

n = (L.length);

for (i = n / 2; i > 0; --i)

heaps(L, i, n);

}

void Sort(Sqlist &L) { //是对 L 中的数据进行排序。

int i;

info X;

Creat(L);

for (i = L.length; i > 1; --i) {

memcpy(&X, &L.data[1], sizeof(info));

memcpy(&L.data[1], &L.data[i], sizeof(info));

memcpy(&L.data[i], &X, sizeof(info));

heaps(L, 1, i - 1);

}

}

3.2 主要算法

  1. Min1 函数
cpp 复制代码
int Min1(int k, int n, int M[100]) {

int j, min = 10000;

for (j = 1; j <= n; j++) {

if (M[j] == 0 && j != k && min > f[j][3])

min = f[j][3];

}

if (min == 10000)

min = f[k][3];

return min;

}

该函数用于获取未被处理且工序时间最短的产品的工序时间,辅助求解最优路径。通过不断调用可在决策节点选择最优路径。

  1. Min2 函数
cpp 复制代码
int Min2(int k, int n, info p) {

int j;

int db, sumf = 0;

for (j = 1; j <= n; j++) {

if (p.M[j] == 0)

sumf = sumf + f[j][2];

}

db = (max(Sum(1, p.g + 1, k, p), Sum(2, p.g, k, p)) + sumf + Min1(k, n, p.M));

return db;

}

该函数用于计算当前节点的最小值,辅助求解最优路径。通过不断调用可在决策节点选择最优路径。

  1. 分支限界法求解最优路径
cpp 复制代码
void fenzhi(int n, Sqlist &L) {

info p, pl, e;

int down = 10000, up = 100000;

int i, j, x, db, sumf = 0, min3 = 100000;

for (i = 1; i <= n; i++) {

for (j = 1; j <= n; j++) {

sumf = sumf + f[j][2];

}

for (j = 1; j <= n; j++) {

if (j != i && min3 > f[j][3])

min3 = f[j][3];

}

db = f[i][1] + sumf + min3;

if (down > db) {

down = db;

x = i;

}

}

e.x = down;

e.M[x] = 1;

e.Lw[1] = x;

e.g = 1;

linsert(L, e);

while (L.length != 0) {

p = GetElem(L);

if (p.Lw[n] != 0) {

e = GetElem(L);

printf("所需最短时间是:%d\n路径是: ", p.x);

for (i = 1; i <= n; i++) {

printf("%d ", p.Lw[i]);

}

} else {

for (i = 1; i <= n; i++) {

pl = p;

if (p.M[i] == 0) {

pl.Lw[p.g + 1] = i;

pl.M[i] = 1;

pl.g = p.g + 1;

pl.x = Min2(i, n, p);

if (pl.x < up) {

linsert(L, pl);

Sort(L);

if (pl.g == n) {

up = pl.x;

deleted(down, up, L);

}

}

}

}

}

}

}

该函数实现分支限界法算法框架,通过生成新路径节点并选择最优路径,最终找到最优路径,输出最短时间和路径。

四、系统运行及结果分析

1. 用户界面

2. 程序运行样例

3. 程序结果分析

对比运行样例输出与手动计算结果,结果相似。同时记录不同 n 值下程序的运行时间,分析随着 n 增大,程序运行时间的变化趋势。若运行时间增长过快,可能需进一步优化算法或数据结构。

五、总结与思考

完成此作业过程中,深入学习了分支限界法及其应用。分支限界法是求解最优化问题的常用算法,通过搜索和剪枝高效寻找最优解。在此问题中,定义数据结构和函数,利用分支限界法搜索解空间,剪去不必要路径找到最优解。编写代码和运行程序过程中,深刻理解了分支限界法思想和实现。发现合理的排序和剪枝策略可大幅减少搜索空间、提高算法效率,且合理设计数据结构和算法能使代码更清晰易理解。此外,认识到编程中错误处理和输入验证的重要性,添加对无效输入的处理避免程序出错。总之,通过解决此问题,掌握了分支限界法应用,加深了对算法设计和错误处理的认识,为今后学习和工作奠定了基础。

相关推荐
EanoJiang2 分钟前
树与二叉树
算法
毛茸茸斑斑点点25 分钟前
补题 (Multiples of 5)
c++
黄雪超31 分钟前
JVM——Java的基本类型的实现
java·开发语言·jvm
VBA633736 分钟前
VBA代码解决方案第二十四讲:EXCEL中,如何删除重复数据行
开发语言
CodeWithMe44 分钟前
【中间件】bthread_基础_TaskControl
c++·中间件
李匠20241 小时前
C++负载均衡远程调用学习之自定义内存池管理
c++·学习
程序猿大波1 小时前
基于Java,SpringBoot,HTML水文水质监测预警系统设计
java·开发语言·spring boot
minji...1 小时前
C语言 指针(2)
c语言·开发语言
姆路1 小时前
Qt官方案例知识点总结(拖放操作——Drag And Drop Robot )
c++·qt
Cuit小唐1 小时前
Qt二维码demo
开发语言·qt·命令模式