你有没有过这种经历?周末去超市大采购,想把最多最实用的东西塞进背包,但又怕超重?或者公司生产计划排不过来,原材料不够用,订单还催得急?其实这些都是运筹学能解决的问题!今天我就用Matlab带大家搞定三个真实场景,看完你会发现——原来运筹学离我们这么近,用Matlab实现起来居然这么简单!
先从最经典的背包问题说起吧!比如我上周去超市,想买5件东西:苹果(2kg,5元)、牛奶(3kg,8元)、面包(5kg,12元)、牛肉(7kg,15元)、鸡蛋(1kg,3元)。我的背包最多装10kg,怎么选才能让买的东西总价值最大?
首先得把这个问题变成Matlab能理解的数学语言: - 变量:用x1到x5表示是否买某件东西,x=1代表买,x=0代表不买(所以是0-1变量) - 目标:最大化总价值 → 5x1+8x2+12x3+15x4+3x5 - 约束:总重量不能超过10kg → 2x1+3x2+5x3+7x4+1x5 ≤10
Matlab里有个专门解决整数线性规划的函数叫intlinprog,不过它默认求最小值,所以我们得把目标函数取负(变成最小化问题)。直接上代码:
```matlab % 背包问题:0-1背包求解 weights = [2,3,5,7,1]; % 物品重量 values = [5,8,12,15,3]; % 物品价值 capacity = 10; % 背包容量
% 定义目标函数(取负因为intlinprog求最小) f = -values; % 整数变量索引(所有变量都是0-1整数) intcon = 1:length(values); % 约束条件:总重量 ≤ capacity A = weights; b = capacity; % 变量上下界(0或1) lb = zeros(length(values),1); ub = ones(length(values),1);
% 求解 [x, fval] = intlinprog(f, intcon, A, b, [], [], lb, ub);
% 结果输出 selected_items = find(x == 1); % 找到选中的物品编号 total_value = -fval; % 转换回最大价值 total_weight = weights * reshape(x,1,length(x)); % 计算总重量
fprintf('选中的物品编号:'); disp(selected_items); fprintf('总价值:%d元\n', total_value); fprintf('总重量:%dkg\n', total_weight); ```
我跑了一下代码,结果是选中了第2、3、5件物品(牛奶、面包、鸡蛋),总价值23元,总重量刚好9kg。你别说,这个组合比我之前凭感觉选的要划算多了!
小提示:我第一次用intlinprog的时候,差点忘了把目标函数转成最小化,结果跑出来的结果完全反了,大家一定要记住这个细节!!!
我朋友开了个小工厂,生产A和B两种零件。A零件每件需要2kg钢材和3小时工时,利润50元;B零件每件需要3kg钢材和2小时工时,利润60元。工厂每周有100kg钢材和120小时工时,怎么安排生产才能让利润最大?
这个问题和背包问题类似,但变量可以是整数(总不能生产半件零件吧): - 变量:x1=每周生产A的数量,x2=每周生产B的数量(都是非负整数) - 目标:最大化利润 →50x1+60x2 - 约束:钢材限制2x1+3x2 ≤100;工时限制3x1+2x2 ≤120;x1≥0,x2≥0
同样用intlinprog函数,代码如下:
```matlab % 生产调度问题 % 目标函数系数(取负求最小) f = [-50; -60]; % 整数变量索引 intcon = [1,2]; % 约束矩阵:钢材和工时 A = [2,3; 3,2]; % 约束上限 b = [100;120]; % 变量下界(不能生产负数) lb = zeros(2,1); % 变量上界(这里设为很大的数,因为没有明确限制) ub = [inf; inf];
% 求解 [x, fval] = intlinprog(f, intcon, A, b, [], [], lb, ub);
% 结果输出 total_profit = -fval; fprintf('每周生产A零件:%d件\n', round(x(1))); fprintf('每周生产B零件:%d件\n', round(x(2))); fprintf('最大利润:%d元\n', total_profit); ```
代码跑出来的结果是生产A零件28件,B零件14件,最大利润是28×50+14×60=2240元。我朋友之前每周生产20件A和20件B,利润只有20×50+20×60=2200元,虽然差得不多,但长期下来也是一笔不小的收入呢!
最后一个场景是物流运输。假设我有两个仓库:仓库1有80吨货,仓库2有100吨货。三个门店需要货物:门店1要50吨,门店2要70吨,门店3要60吨。运费如下表:
| 仓库→门店 | 门店1 | 门店2 | 门店3 | |-----------|-------|-------|-------| | 仓库1 | 10元/吨 |15元/吨 |20元/吨 | | 仓库2 |12元/吨 |18元/吨 |16元/吨 |
怎么安排运输才能让总运费最少?
这个问题叫运输问题,变量比较多,但逻辑很清晰: - 变量:xij=从仓库i运到门店j的货物量(i=1,2;j=1,2,3) - 目标:最小化总运费 →10x11+15x12+20x13+12x21+18x22+16x23 - 约束: - 仓库1的发货量 ≤80 →x11+x12+x13 ≤80 - 仓库2的发货量 ≤100 →x21+x22+x23 ≤100 - 门店1收到的货=50 →x11+x21=50 - 门店2收到的货=70 →x12+x22=70 - 门店3收到的货=60 →x13+x23=60 - 所有xij≥0
这里用linprog函数就可以了(因为运输量可以是小数):
```matlab % 运输问题求解 % 目标函数系数:x11,x12,x13,x21,x22,x23的运费 f = [10,15,20,12,18,16]; % 不等式约束矩阵(仓库发货限制) A = [1,1,1,0,0,0; 0,0,0,1,1,1]; % 不等式约束上限 b = [80;100]; % 等式约束矩阵(门店收货限制) Aeq = [1,0,0,1,0,0; 0,1,0,0,1,0;0,0,1,0,0,1]; % 等式约束值 beq = [50;70;60]; % 变量下界 lb = zeros(6,1);
% 求解 [x, fval] = linprog(f, A, b, Aeq, beq, lb);
% 结果输出 fprintf('从仓库1运到门店1:%.0f吨\n', x(1)); fprintf('从仓库1运到门店2:%.0f吨\n', x(2)); fprintf('从仓库1运到门店3:%.0f吨\n', x(3)); fprintf('从仓库2运到门店1:%.0f吨\n', x(4)); fprintf('从仓库2运到门店2:%.0f吨\n', x(5)); fprintf('从仓库2运到门店3:%.0f吨\n', x(6)); fprintf('总运费:%.0f元\n', fval); ```
代码结果显示:仓库1运50吨到门店1,30吨到门店2;仓库2运40吨到门店2,60吨到门店3。总运费是10×50+15×30+18×40+16×60=500+450+720+960=2630元。这个方案比我朋友之前随便安排的运输方式节省了将近300元!
今天这三个例子都是运筹学里最基础但又超实用的问题。很多人觉得运筹学很高深,但只要从这些小场景入手,把实际问题转化成数学模型,再用Matlab的优化函数跑一下,就能轻松解决。下次遇到类似的问题,别再拍脑袋决定了——用Matlab跑个模型,说不定能给你带来意想不到的收获!
话说回来,Matlab的优化工具箱真的很强大,除了今天用到的intlinprog和linprog,还有很多其他函数比如fmincon(非线性规划)、quadprog(二次规划)等。大家可以根据自己的问题选择合适的工具。
希望这篇文章能帮到正在学习运筹学或Matlab的你!如果有什么问题,欢迎在评论区留言(虽然我这里没法回复,但你可以自己试着查资料解决哦)。下次再见!