蒙特卡洛模拟(4)————书店买书问题(0-1规划)

一、问题提出

二、模型建立

1.符号建立

在图表上,我们可以看见有六家商店和五本书,在代码中我们往往用矩阵来表示这个信息,因此我们需要规定一些符号来表示信息
i=1,2,.....6,表示A,B,.....,F这六家商店
j=1,2...5,表示这B1,B2....,B5五本书
自然,我们规定mij表示j书在i商店的售价,qi表示第i家店的运费
引入0-1变量xij,1表示在第i家店买第j本书,0表示没买。这样的话,用这些0-1数值直接去乘价格矩阵,相加后就可以得到最后的价格

2.规定约束

这个问题的约束相对简单,即每本书只买一本

3.获得目标函数

我们的目标函数就是使得费用最小,而费用有两部分,第一部分是书的价格,第二部分是运费。在代码求解的过程中,我们会介绍利用索引的方法来提取数据,计算运费

三、代码求解

我们如果用计算机模拟,并不需要规定那么多符号,但是计算机模拟也不是万能的。
在这里只有7776(6^5)种情况,我们只需要进行多次模拟即可找到最优解。但如果情况数目更多,只用计算机模拟会导致计算量过大,从而难以找到最优解,因此学会模型的建立也是必须的
下面我们来介绍这个问题的代码部分

1.预备知识

(1)unique函数

unique([1 2 5; 6 8 9;2 4 6])
ans=[1 2 4 5 6 8 9]'
unique函数可以剔除一个矩阵或者向量的重复值,并将结果按照从小到大的顺序排列

(2)randi函数

randi([a,b],m,n)
randi函数可在指定区间[a,b]内随机取出大小为m*n的整数矩阵

2.变量设置与初始化

min_money = +Inf;  % 初始化最小的花费为无穷大,后续只要找到比它小的就更新
min_result = randi([1, 6],1,5);  % 初始化五本书都在哪一家书店购买,后续我们不断对其更新
%若min_result = [5 3 6 2 3],则解释为:第1本书在第5家店买,第2本书在第3家店买,第3本书在第6家店买,第4本书在第2家店买,第5本书在第3家店买  
n = 100000;  % 蒙特卡罗模拟的次数
M = [18	 39	29	48	59
        24	45	23	54	44
        22	45	23	53	53
        28	47	17	57	47
        24	42	24	47	59
        27	48	20	55	53];  % m_ij  第j本书在第i家店的售价
freight = [10 15 15 10 10 15];  % 第i家店的运费

3.输入循环进行模拟

(1)进行循环后,我们首先得到了一个result,之后用unique函数将其排序后,得到了一个由小到大排序的索引向量,将这个向量带入到freight中,就可以得到对应的运费,对其求和得到总运费
(2)然后加上五本书的售价,这个过程需要进行五次循环,第i次循环找出第i列的某个数,而这个数处于result(i)行
(3)之后判断是否小于最小花费,如果小于就更新最小值与最小值结果

for k = 1:n  % 开始循环
    result = randi([1, 6],1,5); % 在1-6这些整数中随机抽取一个1*5的向量,表示这五本书分别在哪家书店购买
    index = unique(result);  % 在哪些商店购买了商品,因为我们等下要计算运费
    money = sum(freight(index)); % 计算买书花费的运费
    % 计算总花费:刚刚计算出来的运费 + 五本书的售价
    for i = 1:5   
        money = money + M(result(i),i);  
    end
    if money < min_money  % 判断刚刚随机生成的这组数据的花费是否小于最小花费,如果小于的话
        min_money = money  % 我们更新最小的花费
        min_result = result % 用这组数据更新最小花费的结果
    end
end
min_money   % 18+39+48+17+47+20
min_result

四、模型拓展

在此模型的基础上加上额外条件,例如:在同一家店买书的价格超过50元包邮或者打折等,这也是现实生活中常见的优惠
在此基础上,我们需要对循环的过程加上更多的限制条件

posted @ 2024-08-04 17:57  卢宇博  阅读(25)  评论(0编辑  收藏  举报