线性规划模型-应用篇

news2024/11/25 7:09:55

文章目录

  • 模型特点
  • 使用技巧
    • 工具包和求解器
    • 模型线性化
  • 应用实例
  • 经验总结

模型特点

上一篇中,详细阐述了线性规划问题和单纯形法的算法原理,本文将着重介绍线性模型在工业场景中的应用。

首先需要说清楚的是,为什么线性模型深受研发人员青睐。

从已有的经验来看,主要原因有三个:(1)线性规划的局部最优解就是全局最优解;(2)计算速度快;(3)研发成本低。

为了说明第一点,需要先引入一个概念:凸函数。

凸函数的定义为:设函数 f f f的定义域是凸集,且对于 θ ∈ [ 0 , 1 ] \theta\in[0,1] θ[0,1] f f f上任意两点 x x x y y y均满足
f ( θ x + ( 1 − θ ) y ) ≤ θ f ( x ) + ( 1 − θ ) f ( y ) f(\theta x + (1-\theta)y) ≤ \theta f(x) + (1-\theta)f(y) f(θx+(1θ)y)θf(x)+(1θ)f(y)
则称函数 f f f为凸函数。下图是一个凸函数的示意图,显然用直线连接函数上的任意两点A和B,线段AB上的点都在函数的上方。

在线性规划问题中,目标函数为线性加和的表达式,显然也是凸函数。

有了这个概念后,我们做以下推演:

假设 x ⋆ x^\star x是线性规划问题的一个局部最优解,即在 x ⋆ x^\star x附近存在一个邻域,在该邻域内所有的点都比 f ( x ⋆ ) f(x^\star) f(x)大。

此时构造一个新的 x = ( 1 − t ) x ⋆ + t y x=(1-t)x^\star + ty x=(1t)x+ty,只要 t t t足够小,那么 x x x就能出现在 x ⋆ x^\star x的邻域内,即
f ( x ⋆ ) ≤ f ( ( 1 − t ) x ⋆ + t y ) f(x^\star)≤f((1-t)x^\star + ty) f(x)f((1t)x+ty)
由于 f f f是凸函数,所以必然满足
f ( ( 1 − t ) x ⋆ + t y ) ≤ ( 1 − t ) f ( x ⋆ ) + t f ( y ) f((1-t) x^\star + ty) ≤(1-t) f(x^\star) + tf(y) f((1t)x+ty)(1t)f(x)+tf(y)
上面两式结合一下,同时消去 f ( x ⋆ ) f(x^\star) f(x),可以得到
f ( x ⋆ ) ≤ f ( y ) f(x^\star)≤f(y) f(x)f(y)
由于 y y y是任意的,所以 x ⋆ x^\star x是全局最优解。

这就意味着,不管使用哪个策略,只要找到了一个局部最优解,那就肯定也是全局最优解。

针对计算速度快的说明,有些复杂,这里直接给出结论:针对线性规划问题,使用单纯形法求解,最差情况下是指数级复杂度,但平均复杂度是多项式时间;如果使用内点法求解,是多项式复杂度。

至于研发成本,在下一节中将会看到,在商用/开源求解器的加持下,主要研发成本只剩下问题建模和模型代码化。

使用技巧

得益于上述特点,研发人员会遇到优化问题时,会想方设法地使用线性模型。那么具体到任意一个场景,该如何使用线性模型呢?

工具包和求解器

此前我们已经提过,单纯形法是求解线性规划问题的高效算法,但是在实际应用时,我们并不需要像运筹学教材里描述的那样,去手撕单纯形表。这主要是因为,目前已经有非常多的求解器可以辅助我们做模型的优化计算。文章中列举了很多求解器,这里做个简单汇总。

商用求解器开源求解器其他软件集成
Gurobi,Cplex,Xpress,Mosek, BARON, Lingo, COPT, MindOPT, OPTVSCIP,Coin-OR套件CLP/CBC/CGL/SYMPHONY,LP_solve, GLPK,OR-Tools,CMIP, LeavesMATLAB,SAS,SCIPy,Excel

总体上来说,商业求解器的求解能力是最强的,主要体现在可解决的问题类型多和计算速度快两个方面;开源求解器的求解能力次之,不过根据我个人的经验,针对0-1规划问题,当优化变量是百万量级时,求解时间差不多是小时量级,所以针对大部分的实际问题,应该是够用的;其他软件集成的求解器基本只能应付小规模的问题,使用率很低。

在排除违规使用学术版商业求解器的情况下,工业场景里用的比较多的是OR-Tools,个人理解应该是大家普遍信赖Google这个品牌。

模型线性化

既然算法实现已经有现成的求解器了,那需要我们做的,其实就只剩两件事了:(1)建立线性规划模型;(2)模型代码化。

本节只说第一个,第二个在下一节中通过一个实例来描述。

回顾一下线性规划的标准型
m i n f ( x ) = c T x s.t A x = b x ≥ 0 min \quad f(\pmb x)=\pmb c^T\pmb x \\ \text{s.t} \quad A\pmb x=\pmb b \\ \quad \quad \pmb x ≥ 0 minf(x)=cTxs.tAx=bx0

其实,这个模型的限制还是挺多的。大部分问题被直接建模后,可能都不满足这些条件。

最普遍的不满足标准型的情况有三种:(1) 约束为不等式;(2)优化目标是最大化表达式;(3)优化变量的范围中包含负数。如果是这些情况,目前的大多数求解器是支持直接输入的,即无需将其变为标准型也不影响正常求解。

如果再复杂一点,就需要对原有的模型做一些额外改造,使其满足线性规划的要求,即模型线性化。得益于大佬们的分享,线性化的方法也已经被提前整理好了,详见文章。这里我也做个简单汇总。

编号非线性表达式
1分段函数
2绝对值函数
3MaxMin/MinMax函数
4逻辑或
5MinMin/MinMin函数
6含有0-1变量的乘积形式
7分式表达式
8max/min函数
9混合整数

也就是说,如果我们的原始模型是以上表中的表达式,那就可以通过一些改造使其变为线性模型。

不过这里还有个偷懒的小技巧,就是有些求解器的功能已经非常强大,允许我们直接输入部分种类的非线性表达式,比如Gurobi就可以直接添加绝对值函数和max函数等。所以如果确定了要使用某个求解器后,可以先了解清楚其支持的表达式种类,再看应该把模型细致到哪个程度。

应用实例

本节以一个线性规划问题为例,详细描述如何使用python调用ortools求解器,顺便给上一节模型线性化的事情填坑。

事实上,ortools的官网上已经有些例子了,但是在刚开始使用时,还是会有一些小问题:问题规模较大时怎么操作;如何判断所建立的模型是否正确等。

为了解答上述疑问,接下来以一个实例来说明。

规模大一些后,手动输入目标函数和约束条件中的系数是不现实的,一般我会提前将这些系数存到一个dataframe中,比如下图中的 A , B , C \pmb A, \pmb B, \pmb C A,B,C


线性模型可以描述为:

(1) 优化变量 x \pmb x x
0 ≤ x i ≤ 1 , i = 0 , . . . , 44 0≤x_i≤1,i=0,...,44 0xi1,i=0,...,44
(2) 目标函数为
m a x [ A − 0.5 B ] T x max \quad [\pmb A-0.5\pmb B]^T\pmb x max[A0.5B]Tx
(3) 约束条件有两组,第一组是
∑ i = 0 8 x 9 j + i = 1 , j = 0 , 1 , . . , 4 \sum_{i=0}^8x_{9j+i}=1, \quad j=0,1,..,4 i=08x9j+i=1,j=0,1,..,4
第二组是
[ B − 0.05 C ] T x ≥ 0 [\pmb B-0.05\pmb C]^T\pmb x ≥ 0 [B0.05C]Tx0

算法实现的全流程包括:声明求解器->定义优化变量、目标函数和约束条件->模型求解->打印模型->输出最优解。我此前用过ortools、pulp和cplex,流程基本是通用的,主要的区别在于具体表达的方式。

ortools的实现代码如下

import pandas as pd
from ortools.linear_solver import pywraplp
import time


if __name__ == '__main__':

    coef_df = pd.read_csv('lp_data.csv')

    # 统计模型计算时间时使用
    time0 = time.time()

    # 声明ortools求解器,使用SCIP算法
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # 优化变量
    x = {}
    for j in range(len(coef_df)):
        x[j] = solver.NumVar(0, 1, 'x[%i]' % j)

    # 目标函数
    obj_expr = [(coef_df['A'].iloc[j] - 0.5 * coef_df['B'].iloc[j]) * x[j] for j in range(len(coef_df))]
    solver.Maximize(solver.Sum(obj_expr))
    # 约束条件一
    for i in range(int(len(coef_df) / 9)):
        constraint_expr = [x[i * 9 + j] for j in range(9)]
        solver.Add(sum(constraint_expr) == 1)

    # 约束条件二
    constraint_expr = [(coef_df['B'].iloc[j] - 0.05 * coef_df['C'].iloc[j]) * x[j] for j in
                       range(len(coef_df))]
    solver.Add(solver.Sum(constraint_expr) >= 0)

    # 模型求解
    status = solver.Solve()

    # 打印模型
    fw = open('ortools output model.lp', 'w', encoding='utf-8')
    fw.write(solver.ExportModelAsLpFormat(True))
    fw.write("\n")

    # 模型求解成功, 打印结果
    if status == pywraplp.Solver.OPTIMAL:
        # 变量最优解
        print('best_x = [')
        for j in range(len(coef_df)):
            print('{:.2f}'.format(x[j].solution_value()), end=" ")
            if (j+1) % 9 == 0 and j+1 < len(coef_df):
                print()
        print(']')

        # 最优目标函数值
        print('best_f =', solver.Objective().Value())

        # 约束条件值
        cons_2 = 0
        for j in range(len(coef_df)):
            cons_2 += x[j].solution_value() * (coef_df['B'].iloc[j] - 0.05 * coef_df['C'].iloc[j])
        print('cons_2 = {:.2f}'.format(cons_2))

    else:
        print('not converge.')

    print('cost time: {}'.format(time.time() - time0))

运行代码后,可以得到优化解如下。

best_x = [
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00 
0.00 0.00 0.00 0.00 0.00 0.00 0.00 0.00 1.00 
0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 
0.00 0.00 0.00 1.00 0.00 0.00 0.00 0.00 0.00 
0.00 0.00 0.53 0.47 0.00 0.00 0.00 0.00 0.00 ]
best_f = 166.72005627038578
cons_2 = 0.00
cost time: 0.08336210250854492

然后在代码所在文件夹中可以找到一个ortools output model.lp文件,打开后内容如下。这里详细展示了我们的模型内容,可以用来校验代码是否都已经编写正确。

\ Generated by MPModelProtoExporter
\   Name             : 
\   Format           : Free
\   Constraints      : 6
\   Variables        : 45
\     Binary         : 0
\     Integer        : 0
\     Continuous     : 45
Maximize
 Obj: +46.67 V00 +46.4646 V01 +46.0351 V02 +45.3817 V03 +44.5044 V04 +43.403 V05 +42.0777 V06 +40.5284 V07 +38.7551 V08 +25.6 V09 +25.1025 V10 +24.5226 V11 +23.8604 V12 +23.1158 V13 +22.2888 V14 +21.3795 V15 +20.3878 V16 +19.3137 V17 +39.8 V18 +38.7454 V19 +37.5924 V20 +36.3409 V21 +34.9909 V22 +33.5425 V23 +31.9956 V24 +30.3502 V25 +28.6064 V26 +35.82 V27 +36.7272 V28 +37.6345 V29 +37.2212 V30 +35.4442 V31 +33.5451 V32 +31.5241 V33 +29.381 V34 +27.1158 V35 +37.8 V36 +36.7733 V37 +35.6558 V38 +34.4474 V39 +33.148 V40 +31.7579 V41 +30.2768 V42 +28.7049 V43 +27.0421 V44 
Subject to
 C0: +1 V00 +1 V01 +1 V02 +1 V03 +1 V04 +1 V05 +1 V06 +1 V07 +1 V08  = 1
 C1: +1 V09 +1 V10 +1 V11 +1 V12 +1 V13 +1 V14 +1 V15 +1 V16 +1 V17  = 1
 C2: +1 V18 +1 V19 +1 V20 +1 V21 +1 V22 +1 V23 +1 V24 +1 V25 +1 V26  = 1
 C3: +1 V27 +1 V28 +1 V29 +1 V30 +1 V31 +1 V32 +1 V33 +1 V34 +1 V35  = 1
 C4: +1 V36 +1 V37 +1 V38 +1 V39 +1 V40 +1 V41 +1 V42 +1 V43 +1 V44  = 1
 C5: -23.3335 V00 -19.5627 V01 -15.3439 V02 -10.6772 V03 -5.5626 V04 -3.55271e-15 V05 +6.01055 V06 +12.469 V07 +19.3755 V08 -12.8 V09 -10.5695 V10 -8.17421 V11 -5.61421 V12 -2.88947 V13 +3.05421 V15 +6.27315 V16 +9.65684 V17 -19.9 V18 -16.3139 V19 -12.5308 V20 -8.5508 V21 -4.37387 V22 +4.5708 V24 +9.33853 V25 +14.3032 V26 -12.091 V27 -12.3972 V28 -12.7035 V29 -10.3686 V30 -5.30634 V31 +5.55041 V33 +11.3449 V34 +17.3834 V35 -18.9 V36 -15.4835 V37 -11.8853 V38 -8.10526 V39 -4.14351 V40 +4.32526 V42 +8.83227 V43 +13.521 V44  >= 0
Bounds
 0 <= V00 <= 1
 0 <= V01 <= 1
 0 <= V02 <= 1
 0 <= V03 <= 1
 0 <= V04 <= 1
 0 <= V05 <= 1
 0 <= V06 <= 1
 0 <= V07 <= 1
 0 <= V08 <= 1
 0 <= V09 <= 1
 0 <= V10 <= 1
 0 <= V11 <= 1
 0 <= V12 <= 1
 0 <= V13 <= 1
 0 <= V14 <= 1
 0 <= V15 <= 1
 0 <= V16 <= 1
 0 <= V17 <= 1
 0 <= V18 <= 1
 0 <= V19 <= 1
 0 <= V20 <= 1
 0 <= V21 <= 1
 0 <= V22 <= 1
 0 <= V23 <= 1
 0 <= V24 <= 1
 0 <= V25 <= 1
 0 <= V26 <= 1
 0 <= V27 <= 1
 0 <= V28 <= 1
 0 <= V29 <= 1
 0 <= V30 <= 1
 0 <= V31 <= 1
 0 <= V32 <= 1
 0 <= V33 <= 1
 0 <= V34 <= 1
 0 <= V35 <= 1
 0 <= V36 <= 1
 0 <= V37 <= 1
 0 <= V38 <= 1
 0 <= V39 <= 1
 0 <= V40 <= 1
 0 <= V41 <= 1
 0 <= V42 <= 1
 0 <= V43 <= 1
 0 <= V44 <= 1
End


经验总结

作为一个工作了近3年的运筹优化算法工程师,对线性模型的工程应用算是比较熟悉的了。本节以场景对计算实时性的高低来做区分,分别描述个人的认知和经验。

对于那些实时性要求不高、更追求最优性的场景,比如路径规划、生产排程、排班定编等场景,只需每天、每周、甚至每月调度一次,可以考虑直接使用线性模型。

不过为了保证线上流程的稳定性,这类算法在设计时一般都需要额外增加一个兜底的启发式算法,这样的话,即使线性模型在特殊情况下无法在给定时间内输出最优解,也可以让启发式解决算法及时透出一个可行解。

对于那些实时性要求高的场景,比如骑手派单算法,一般更适合使用启发式算法。但即使是在这种情况下,线性模型依然具有重要价值:离线评估启发式算法的最优性,定量给出已有算法解和最优解之间的gap。gap的表达形式可能是这样的:变量数小于等于10时,针对随机生成/历史上的100个问题实例,启发式算法100%可以找到最优解,计算耗时和线性模型相当;当变量数增长至30时,启发式算法可以找到80%的最优解,计算耗时约为线性模型的10%,未找到最优解的问题中,gap的均值10%;当变量数增长至50时,启发式算法可以找到30%的最优解,计算耗时约为线性模型的1%,未找到最优解的问题中,gap约50%。

对于前者,模型研发完后几乎就没有多少改进空间,虽然可能还有相关的事情要做,比如模型的部分输入内容包含预测数据,存在数据不准确现象;落地过程中遭遇业务阻力,推广不那么顺利等,但是这些问题的解决,都不再是算法方面的进展,所以本质上是很费场景的,也就是说,要想持续有算法进展,可能就需要研发人员频繁寻找新场景。

但是对于后者,由于可以在优化gap的方向持续做功,比如提升计算速度、降低与最优解之间的gap等,所以相对来说,算法方面可以做的事情就稍微多一些。不过,需要谨防的陷阱是,只关注gap值的自身变化,而忽略了gap对业务的影响。一般情况下,gap减少的难度是递增的,对业务的影响却是递减的,所以当gap减少到一定程度,可能就没有再继续优化的必要了,是否已经达到临界点需要时刻思考。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/873211.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

五、约束编程求解优化问题

文章目录 1、瑶草问题-离散优化问题2、重试优化3、分支限界法-改进重试优化法4、重启式搜索4.1 重启方针/策略4.2 自动化搜索策略 THE END 1、瑶草问题-离散优化问题 \qquad 要求在一个建木上构建一个完整的分枝树&#xff0c;每一个完整的分枝有100段&#xff0c;完整分枝上的…

2023年《开学第一课》播出时间是什么时候?开学第一课怎么在手机上观看高清直播?

2023年《开学第一课》播出时间是什么时候&#xff1f; 根据往年《开学第一课》播出时间预计2023年《开学第一课》播出时间是2023年9月1日20:00&#xff0c;如有变化请以官方公布为准&#xff1b; 2023年开学第一课怎么在手机上观看高清直播&#xff1f; 1、打开手机微信&…

第三章,矩阵,07-用初等变换求逆矩阵、矩阵的LU分解

第三章&#xff0c;矩阵&#xff0c;07-用初等变换求逆矩阵、矩阵的LU分解 一个基本的方法求 A − 1 B A^{-1}B A−1BLU分解例1&#xff0c;求矩阵A的LU分解&#xff1a;例12&#xff0c;LU分解解线性方程组&#xff1a; 玩转线性代数(19)初等矩阵与初等变换的相关应用的笔记&a…

Rx.NET in Action 第一章学习笔记

Part 1 初入反应式扩展 什么是反应式程序&#xff1f;它们有什么用&#xff1f;使用反应式扩展&#xff08;Rx&#xff09;编程&#xff0c;会如何改变你编写代码的方式&#xff1f;在开始使用 Rx 之前应该做些什么&#xff1f;为什么 Rx 比传统的事件驱动编程更好&#xff1f…

简单认识Zabbix监控系统及配置

文章目录 一、zabbix概述1、定义2、zabbix监控原理3、监控对象4、zabbix的3种架构&#xff08;1&#xff09; C/S架构&#xff08;2&#xff09;分布式架构&#xff1a;zabbix-proxy-client架构&#xff08;3&#xff09; master-node-client架构 5、zabbix监控模式 二、部署za…

Apollo Planning2.0决策规划算法代码详细解析 (1):环境搭建

背景: apollo开源团队近期更新了planning版本,对代码进行了一定程度上的重构。 重构后代码结构更加清晰,对扩展更为友好;此外,也更新了dreamview对pnc的支持,使得调试更加方便。 本教程将继续更新对于Apollo Planning2.0决策规划算法代码的详细解析,便于大家更好理解…

[鹏城杯 2022]简单包含

直接用php&#xff1a;// 有wtf 加脏数据绕过

Spring boot中的线程池-ThreadPoolTaskExecutor

一、jdk的阻塞队列&#xff1a; 二、Spring boot工程的有哪些阻塞队列呢&#xff1f; 1、默认注入的ThreadPoolTaskExecutor 视频解说&#xff1a; 线程池篇-springboot项目中的service层里简单注入ThreadPoolTaskExecutor并且使用_哔哩哔哩_bilibili 程序代码&#xff1a;…

Impala实践:解析glog打印的 C++ 报错堆栈

Impala实践&#xff1a;解析glog打印的 C 报错堆栈 Impala使用glog生成日志。生产环境用的都是release build&#xff0c;glog产生的报错堆栈里没有函数名&#xff0c;很难像Java报错堆栈那样方便定位问题。下面是 Impalad 日志中的一个报错&#xff1a; I0522 09:07:16.0020…

浅复制和深复制(使用python)

在编程语言中&#xff0c;复制通常是通过赋值操作来实现的。具体实现方式可能因编程语言而异。 1. 浅复制&#xff08;Shallow Copy&#xff09; 浅复制是指创建一个新对象&#xff0c;新对象的内容是原始对象的引用。换句话说&#xff0c;新对象和原始对象共享相同的数据&am…

【JVM】JVM 调优的参数都有哪些?

文章目录 1. 设置堆空间大小2. 虚拟机栈的设置3. 年轻代中Eden区和两个Survivor区的大小比例4. 年轻代晋升老年代阈值5. 设置垃圾回收收集器 1. 设置堆空间大小 设置堆的初始大小和最大大小&#xff0c;为了防止垃圾收集器在初始大小、最大大小之间收缩堆而产生额外的时间&…

【Linux系统编程】21.echo、env、fork、getpid、getppid

目录 echo PATH SHELL TERM LANG HOME env fork 返回值 getpid getppid 测试代码1 测试结果 测试代码2 测试结果 父子进程相同 父子进程不同 父子进程共享 echo 查看单个环境变量。 PATH 可执行文件的搜索路径。 SHELL 当前Shell。 TERM 当前终端类型。终端…

一休休的面试题

重点面试题(今天又看了很多的博客大概有个三十来篇吧所以总结了一休休的面试题)&#xff1a; ps:已经入秋了为什么还是这么热&#xff01;&#xff01;&#xff01; 1、受管 bean 的生命周期 对于普通的 Java 对象&#xff0c;new 的时候会去创建对象&#xff0c;而当它没有…

Redis进阶(3)——在Linux上基于Docker容器Redis搭建一主二从三哨兵 SpringBoot整合Redis哨兵

目录 引出redis主从搭建&#xff1a;一主2从6389Master准备文件redis.confredis.log日志文件运行容器查看日志方式tail 6390Slave6391Slave 创建3哨兵创建文件夹sentinel创建运行哨兵容器问题&#xff1a;脑裂问题 SpringBoot整合Redis哨兵启动1主2从&#xff0c;3哨兵pom.xml文…

聊聊服务端缓存那些事(预热、淘汰、污染、雪崩、穿透、击穿等)

文章目录 概要一、缓存预热二、缓存污染2.1、先更新数据库再更新缓存2.2、先更新缓存再更新数据库2.3、先删除缓存再更新数据库&#xff0c;读时再更新2.4、先更新数据库再删除缓存&#xff0c;读时再更新2.5、缓存污染总结2.6、删除缓存失败了怎么办&#xff1f;2.7、延迟双删…

【数据结构与算法】十大经典排序算法-堆排序

&#x1f31f;个人博客&#xff1a;www.hellocode.top &#x1f3f0;Java知识导航&#xff1a;Java-Navigate &#x1f525;CSDN&#xff1a;HelloCode. &#x1f31e;知乎&#xff1a;HelloCode &#x1f334;掘金&#xff1a;HelloCode ⚡如有问题&#xff0c;欢迎指正&#…

JZ33二叉搜索树的后序遍历序列

题目地址&#xff1a;二叉搜索树的后序遍历序列_牛客题霸_牛客网 题目回顾&#xff1a; 解题思路&#xff1a; 使用栈 栈的特点是&#xff1a;先进后出。 通读题目后&#xff0c;我们可以得出&#xff0c;二叉搜索树是左子节点小于根节点&#xff0c;右子节点大于根节点。 …

wps设置一键标题字体和大小

参考 wps设置一键标题字体和大小&#xff1a;https://www.kafan.cn/A/7v5le1op3g.html 统一一键设置

[FPGA IP系列] 2分钟了解FPGA中的BRAM

FPGA设计中&#xff0c;BRAM是一项非常关键的内置存储资源&#xff0c;FPGA开发需要熟练使用BRAM&#xff0c;今天再复习一下BRAM的知识&#xff0c;包括BRAM的定义、组成、应用等等。 一、BRAM介绍 1、BRAM的定义 RAM是Random Access Memory&#xff0c;也就是随机访问数据…

C字符串练习题(6.3.1)

编写一个程序&#xff0c;从键盘上读入一个小于1000的正整数&#xff0c;然后创建并输出一个字符串&#xff0c;说明该整数的值。例如&#xff0c;输入941&#xff0c;程序产生的字符串是“Nine hundred and forty one”。 #include<stdlib.h> #include<string.h>…