蒙特卡羅(洛)模擬



title: 蒙特卡羅(洛)模擬
date: 2020-02-27 21:26:53
categories: 數學建模
tags: [ MATLAB, 模擬]
mathjax: true


引例

布豐投針實驗

法國數學家布豐(1707-1788)最早設計了投針試驗。

這一方法的步驟是:

1) 取一張白紙,在上面畫上許多條間距為a的平行線。

2) 取一根長度為l(l≤a) 的針,隨機地向畫有平行直線的紙上擲n次,觀察針與直線相交的次數,記為m。

3)計算針與直線相交的概率.

18世紀,法國數學家布豐提出的“投針問題”,記載於布豐1777年出版的著作中:“在平面上畫有一組間距為a的平行線,將一根長度為l(l≤a)的針任意擲在這個平面上,求此針與平行線中任一條相交的概率。”

布豐本人證明了,這個概率是:

\[p=\frac{2l}{\pi a} \]

(其中π為圓周率

由於它與π有關,於是人們想到利用投針試驗來估計圓周率的值。

布豐驚奇地發現:有利的扔出與不利的扔出兩者次數的比,是一個包含π的表示式.如果針的長度等於a/2,那么有利扔出的概率為1/π.扔的次數越多,由此能求出越為精確的π的值。

下面是利用這個公式,用概率的方法得到圓周率的近似值的一些資料。

試驗者 時間 投擲次數 相交次數 圓周率估計值
Wolf 1850年 5000 2532 3.1596
Smith 1855年 3204 1218.5 3.1554
C.De Morgan 1860年 600 382.5 3.137
Fox 1884年 1030 489 3.1595
Lazzerini 1901年 3408 1808 3.1415929
Reina 1925年 2520 859 3.1795

證明

代碼

%%  蒙特卡羅用於布豐投針實驗

%% (1)預備知識
%  rand(m,n)函數產生由在[0,1]之間均勻分布的隨機數組成的m行n列的矩陣(或稱為數組)。
rand(5,4)
%     0.8300    0.1048    0.2396    0.4398
%     0.5663    0.1196    0.8559    0.5817
%     0.9281    0.2574    0.3013    0.9355
%     0.3910    0.3173    0.2108    0.1676
%     0.3645    0.4372    0.8819    0.9232
rand(3) % 若只給一個輸入,則會生成一個方陣
%     0.1709    0.4951    0.0541
%     0.9374    0.8500    0.6155
%     0.2400    0.3156    0.5741
% a + rand(m,n)*(b-a) 可以輸出在[a,b]之間均勻分布的隨機數組成的m行n列的矩陣。
-2 + rand(3,2) * (2 - (-2))  % 輸出在[-2,2]之間均勻分布的隨機數組成的3行2列的矩陣。
%    -1.2743    0.6013
%    -1.3084    0.0766
%     1.5075    0.7563
% a + rand(m,n)*(b-a)等價於unifrnd(a,b,m,n)
unifrnd(-2,2,3,2)

%% (2)代碼部分
l =  0.520;     % 針的長度(任意給的)
a = 1.314;    % 平行線的寬度(大於針的長度l即可)
n = 1000000;    % 做n次投針試驗,n越大求出來的pi越准確
m = 0;    % 記錄針與平行線相交的次數
x = rand(1, n) * a / 2 ;   % 在[0, a/2]內服從均勻分布隨機產生n個數, x中每一個元素表示針的中點和最近的一條平行線的距離
phi = rand(1, n) * pi;    % 在[0, pi]內服從均勻分布隨機產生n個數,phi中的每一個元素表示針和最近的一條平行線的夾角
% axis([0,pi, 0,a/2]);   box on;  % 畫一個坐標軸的框架,x軸位於0-pi,y軸位於0-a/2, 並打開圖形的邊框
for i=1:n  % 開始循環,依次看每根針是否和直線相交
    if x(i) <= l / 2 * sin(phi (i))     % 如果針和平行線相交
        m = m + 1;    % 那么m就要加1
%         plot(phi(i), x(i), 'r.')   % 模仿書上的那個圖,橫坐標為phi,縱坐標為x , 用紅色的小點進行標記
%         hold on  % 在原來的圖形上繼續繪制
    end
end
p = m / n;    % 針和平行線相交出現的頻率
mypi = (2 * l) / (a * p);  % 我們根據公式計算得到的pi
disp(['蒙特卡羅方法得到pi為:', num2str(mypi)])


%% (3) 由於一次模擬的結果具有偶然性,因此我們可以重復100次后再來求一個平均的pi
result = zeros(100,1);  % 初始化保存100次結果的矩陣
l =  0.520;     a = 1.314;
n = 1000000;    
for num = 1:100
    m = 0;  
    x = rand(1, n) * a / 2 ;
    phi = rand(1, n) * pi;
    for i=1:n
        if x(i) <= l / 2 * sin(phi (i))
            m = m + 1;
        end
    end
    p = m / n;
    mypi = (2 * l) / (a * p);
    result(num) = mypi;  % 把求出來的myphi保存到結果矩陣中
end
mymeanpi = mean(result);  % 計算result矩陣中保存的100次結果的均值
disp(['蒙特卡羅方法得到pi為:', num2str(mymeanpi)])

蒙特卡羅方法概述

定義

​ 蒙特卡羅⽅法⼜稱統計模擬法,是⼀種隨機模擬⽅法,以概率和統計理論⽅法為基礎的⼀種計算⽅法,是使⽤隨機數 (或更常⻅的偽隨機數)來解決很多計算問題的⽅法。將所求解的問題同⼀定的概率模型相聯系,⽤電⼦計算機實現統計模擬或抽樣,以獲得問題的近似解。為象征性地表明這⼀⽅法的概率統計特征,故借⽤賭城蒙特卡羅命名。

提出

​ 蒙特卡羅⽅法於20世紀40年代美國在第⼆次世界⼤戰中研制原⼦彈的“曼哈頓計划”計划的成員S.M.烏拉姆和J. 馮·諾伊曼⾸先提出。數學家馮·諾伊曼⽤馳名世界的賭城—摩納哥的Monte Carlo—來命名這種⽅法,為它蒙上了⼀ 層神秘⾊彩。在這之前,蒙特卡羅⽅法就已經存在。1777年,法國Buffon提出⽤投針實驗的⽅法求圓周率,這被認 為是蒙特卡羅⽅法的起源。

原理

由⼤數定理可知,當樣本容量⾜夠⼤時,事件的發⽣頻率即為其概率。

討論

  1. 蒙特卡羅是⼀種算法嗎 ?

    算法(Algorithm)是指解題⽅案的准確⽽完整的描述,是⼀系列解決問題的清晰指令。蒙特卡羅准確的來說只是⼀ 種思想,或者是是⼀種⽅法。如果我們所求解的問題與概率模型有⼀定的關聯,那么我們就可以使⽤計算機多次模擬事 件發⽣,以獲得問題的近似解。從數學建模⻆度來看,⼤家千萬別認為蒙特卡羅有⼀個通⽤的代碼。每個問題對應的代 碼都是不同的,我們分析清楚題⽬后,就要⾃⼰進⾏編寫適⽤於這個題⽬的代碼。

  2. 蒙特卡羅與計算機仿真的關系

    計算機仿真(模擬)早期稱為蒙特卡羅⽅法,是⼀⻔利⽤隨機數實驗求解隨機問題的⽅法,其主要應⽤在復雜問題的數 值模擬上。但隨着計算機的性能的提⾼以及各種新興產業的發展,⽬前計算機仿真涉及的內容要⼴得多,例如過程控制、動 畫仿真、圖像靜態模擬等都屬於計算機仿真的應⽤(例如⽤計算機模擬原⼦彈爆炸的過程、使⽤計算機⽣成特效⼤⽚等)。 在數學建模中,我們不⽤刻意的去區分兩者的區別,⼤家只需要知道如何使⽤計算機對問題進⾏模擬即可。

  3. 蒙特卡羅與枚舉法

    枚舉法是我們中學就接觸的算法,就是把所有可能發⽣情況都考慮進去,最終計算出來⼀個確定結果。這就與蒙特卡羅 ⽅法的想法很類似,蒙特卡羅法模擬的次數越多,計算的就越准確。由於⽣活中有許多事件發⽣的結果都有⽆限種可能(例如⼀個連續分布的取值),因此我們不可能枚舉出所有的結果,這時候就只能通過蒙特卡羅模擬,將⼀個不確定性的問題轉 化成很多個確定性問題,並得到⼀個近似解,因此蒙特卡羅算法也可以看成是枚舉法的⼀種變異。

已經學過的例⼦

第⼀期 視頻 (AOL) 第七講 : 多元回歸分析

探究內⽣性對回歸結果的影響

第⼀期 視頻 (AOL) 番外篇 : 基於熵權法對印的模型的修正

信息熵和標准差的關系

蒙特卡羅⽅法 的應⽤實例

三⻔問題

​ 你參加⼀檔電視節⽬,節⽬組提供了ABC三扇⻔, 主持⼈告訴你,其中⼀扇⻔后邊有輛汽⻋,其它兩扇⻔ 后是空的。 假如你選擇了B⻔,這時,主持⼈打開了C⻔,讓你 看到C⻔后什么都沒有,然后問你要不要改選A⻔?

有約束的⾮線性規划問題

代碼

%%  蒙特卡羅求解有約束的非線性規划問題
% max f(x) = x1*x2*x3
% s.t.
% (1) -x1+2*x2+2*x3>=0
% (2) x1+2*x2+2*x3<=72
% (3) x2<=20 & x2>=10
% (4) x1-x2 == 10

%% (1)預備知識
%  (1) format long g  可以將Matlab的計算結果顯示為一般的長數字格式(默認會保留四位小數,或使用科學計數法)
5/7
5895*514100
format long g
5/7
5895*514100
%  (2)unifrnd(a,b,m,n)可以輸出在[a,b]之間均勻分布的隨機數組成的m行n列的矩陣。(等價於 a + rand(m,n)*(b-a))
unifrnd(0,5,4,3)
%           4.07361843196589          3.16179623112705          4.78753417717149
%            4.5289596853781         0.487702024997048          4.82444267599638
%           0.63493408146753          1.39249109433524         0.788065408387741
%            4.5668792806951          2.73440759602492          4.85296390880308

%% (2)代碼部分
clc,clear;
tic %計算tic和toc中間部分的代碼的運行時間
n=10000000; %生成的隨機數組數
x1=unifrnd(20,30,n,1);  % 生成在[20,30]之間均勻分布的隨機數組成的n行1列的向量構成x1
x2=x1 - 10;
x3=unifrnd(-10,16,n,1);  % 生成在[-10,16]之間均勻分布的隨機數組成的n行1列的向量構成x3
fmax=-inf; % 初始化函數f的最大值為負無窮(后續只要找到一個比它大的我們就對其更新)
for i=1:n
    x = [x1(i), x2(i), x3(i)];  %構造x向量, 這里千萬別寫成了:x =[x1, x2, x3]
    if (-x(1)+2*x(2)+2*x(3)>=0)  &  (x(1)+2*x(2)+2*x(3)<=72)     % 判斷是否滿足條件
        result = x(1)*x(2)*x(3);  % 如果滿足條件就計算函數值
        if  result  > fmax  % 如果這個函數值大於我們之前計算出來的最大值
            fmax = result;  % 那么就更新這個函數值為新的最大值
            X = x;  % 並且將此時的x1 x2 x3保存到一個變量中
        end
    end
end
disp(strcat('蒙特卡羅模擬得到的最大值為',num2str(fmax)))
disp('最大值處x1 x2 x3的取值為:')
disp(X)
toc %計算tic和toc中間部分的代碼的運行時間


%% (3)縮小范圍重新模擬得到更加精確的取值
clc,clear;
tic %計算tic和toc中間部分的代碼的運行時間
n=10000000; %生成的隨機數組數
x1=unifrnd(22,23,n,1);  % 生成在[22,23]之間均勻分布的隨機數組成的n行1列的向量構成x1
x2=x1 - 10;
x3=unifrnd(11,13,n,1);  % 生成在[11,13]之間均勻分布的隨機數組成的n行1列的向量構成x3
fmax=-inf; % 初始化函數f的最大值為負無窮(后續只要找到一個比它大的我們就對其更新)
for i=1:n
    x = [x1(i), x2(i), x3(i)];  %構造x向量, 這里千萬別寫成了:x =[x1, x2, x3]
    if (-x(1)+2*x(2)+2*x(3)>=0)  &  (x(1)+2*x(2)+2*x(3)<=72)     % 判斷是否滿足條件
        result = x(1)*x(2)*x(3);  % 如果滿足條件就計算函數值
        if  result  > fmax  % 如果這個函數值大於我們之前計算出來的最大值
            fmax = result;  % 那么就更新這個函數值為新的最大值
            X = x;  % 並且將此時的x1 x2 x3保存到一個變量中
        end
    end
end
disp(strcat('蒙特卡羅模擬得到的最大值為',num2str(fmax)))
disp('最大值處x1 x2 x3的取值為:')
disp(X)
toc %計算tic和toc中間部分的代碼的運行時間

書店 買書 問題 ( 0 - 1 規划)(無腦)

%% 書店買書問題的蒙特卡羅的模擬
%% (1)預備知識
% (1)unique函數: 剔除一個矩陣或者向量的重復值,並將結果按照從小到大的順序排列  
% adj.	唯一的; 獨一無二的   [ju'ni:k]
unique([1 2 5; 6 8 9;2 4 6])   
unique([5 6 8 8 4 1 6 2 2 4 8 4 5 6])

% (2)randi([a,b],m,n)函數可在指定區間[a,b]內隨機取出大小為m*n的整數矩陣
randi([-5,5],2,6)

%% (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家店的運費
for k = 1:n  % 開始循環
    result = k([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

導彈追蹤問題

%%  蒙特卡羅用於模擬導彈追擊問題
clear;clc
%% (1)預備知識
% mod(m,n)表示求m/n的余數
mod(8,3)
mod(1000,50)

% 設置橫縱坐標的范圍並標上字符
x = 1:0.01:3;
y = x .^ 2;
plot(x,y)  % 畫出x和y的圖形
axis([0 3 0 10])  % 設置橫坐標范圍為[0, 3] 縱坐標范圍為[0, 10]
pause(3)  % 暫停3秒后再繼續接下來的命令
text(2,4,'清風')  % 在坐標為(2,4)的點上標上字符串:清風
close % 關閉圖形窗口



%% (2) 代碼求解
% 1. 不畫追擊的示意圖
clear;clc
v=200; % 任意給定B船的速度(后期我們可以再改的)
dt=0.0000001; % 定義時間間隔
x=[0,20]; % 定義導彈和B船的橫坐標分別為x(1)和x(2)
y=[0,0]; % 定義導彈和B船的縱坐標分別為y(1)和y(2)
t=0; % 初始化導彈擊落B船的時間
d=0; % 初始化導彈飛行的距離
m=sqrt(2)/2;   % 將sqrt(2)/2定義為一個常量,使后面看起來很簡潔
dd=sqrt((x(2)-x(1))^2+(y(2)-y(1))^2); % 導彈與B船的距離
while(dd>=0.001)  % 只要兩者的距離足夠大,就一直循環下去。(兩者距離足夠小時表示導彈擊中,這里的臨界值要結合dt來取,否則可能導致錯過交界處的情況)
    t=t+dt; % 更新導彈擊落B船的時間
    d=d+3*v*dt; % 更新導彈飛行的距離
    x(2)=20+t*v*m;  y(2)=t*v*m;   % 計算新的B船的位置 (注:m=sqrt(2)/2)
    dd=sqrt((x(2)-x(1))^2+(y(2)-y(1))^2);  % 更新導彈與B船的距離
    tan_alpha=(y(2)-y(1))/(x(2)-x(1));   % 計算斜率,即tan(α)
    cos_alpha=sqrt(1/(1+tan_alpha^2));   % sec(α)^2 = (1+tan(α)^2)
    sin_alpha=sqrt(1-cos_alpha^2);  % sin(α)^2 +cos(α)^2 = 1
    x(1)=x(1)+3*v*dt*cos_alpha;   y(1)=y(1)+3*v*dt*sin_alpha; % 計算新的導彈的位置
    if d>50  % 導彈的有效射程為50個單位
        disp('導彈沒有擊中B船');
        break;  % 退出循環
    end
    if d<=50 & dd<0.001   % 導彈飛行的距離小於50個單位且導彈和B船的距離小於0.001(表示擊中)
        disp(['導彈飛行',num2str(d),'單位后擊中B船'])
        disp(['導彈飛行的時間為',num2str(t*60),'分鍾'])
    end
end

% 2. 畫追擊的示意圖
clear;clc
v=200; % 任意給定B船的速度(后期我們可以再改的)
dt=0.0000001; % 定義時間間隔
x=[0,20]; % 定義導彈和B船的橫坐標分別為x(1)和x(2)
y=[0,0]; % 定義導彈和B船的縱坐標分別為y(1)和y(2)
t=0; % 初始化導彈擊落B船的時間
d=0; % 初始化導彈飛行的距離
m=sqrt(2)/2;   % 將sqrt(2)/2定義為一個常量,使后面看起來很簡潔
dd=sqrt((x(2)-x(1))^2+(y(2)-y(1))^2); % 導彈與B船的距離
for i=1:2
    plot(x(i),y(i),'.k','MarkerSize',1);  % 畫出導彈和B船所在的坐標,點的大小為1,顏色為黑色(k),用小點表示
    grid on;  % 打開網格線
    hold on;  % 不關閉圖形,繼續畫圖
end
axis([0 30 0 10])  % 固定x軸的范圍為0-30  固定y軸的范圍為0-10
k = 0;  % 引入一個變量  為了控制畫圖的速度(因為Matlab中畫圖的速度超級慢)
while(dd>=0.001)  % 只要兩者的距離足夠大,就一直循環下去。(兩者距離足夠小時表示導彈擊中,這里的臨界值要結合dt來取,否則可能導致錯過交界處的情況)
    t=t+dt; % 更新導彈擊落B船的時間
    d=d+3*v*dt; % 更新導彈飛行的距離
    x(2)=20+t*v*m;  y(2)=t*v*m;   % 計算新的B船的位置 (注:m=sqrt(2)/2)
    dd=sqrt((x(2)-x(1))^2+(y(2)-y(1))^2);  % 更新導彈與B船的距離
    tan_alpha=(y(2)-y(1))/(x(2)-x(1));   % 計算斜率,即tan(α)
    cos_alpha=sqrt(1/(1+tan_alpha^2));   % 利用公式:sec(α)^2 = (1+tan(α)^2)  計算出cos(α)
    sin_alpha=sqrt(1-cos_alpha^2);  % 利用公式: sin(α)^2 +cos(α)^2 = 1  計算出sin(α)
    x(1)=x(1)+3*v*dt*cos_alpha;   y(1)=y(1)+3*v*dt*sin_alpha;   % 計算新的導彈的位置
    k = k +1 ;  
    if mod(k,500) == 0   % 每刷新500次時間就畫出下一個導彈和B船所在的坐標  mod(m,n)表示求m/n的余數
        for i=1:2
            plot(x(i),y(i),'.k','MarkerSize',1);
            hold on; % 不關閉圖形,繼續畫圖
        end
        pause(0.001);  % 暫停0.001s后再繼續下面的操作
    end
    if d>50  % 導彈的有效射程為50個單位
        disp('導彈沒有擊中B船');
        break;  % 退出循環
    end
    if d<=50 & dd<0.001   % 導彈飛行的距離小於50個單位且導彈和B船的距離小於0.001(表示擊中)
        disp(['導彈飛行',num2str(d),'個單位后擊中B船'])
        disp(['導彈飛行的時間為',num2str(t*60),'分鍾'])
    end
end

作業

作業1

%%  蒙特卡羅求解非線性規划問題
% min f(x) =2*(x1^2)+x2^2-x1*x2-8*x1-3*x2
% s.t.
% (1) 3*x1+x2>9
% (2) x1+2*x2<16
% (3) x1>0 & x2>0

%% (1)初次尋找最小值的代碼
clc,clear;
format long g   %可以將Matlab的計算結果顯示為一般的長數字格式(默認會保留四位小數,或使用科學計數法)
tic %計算tic和toc中間部分的代碼的運行時間
n=10000000; %生成的隨機數組數
x1=unifrnd(0,16,n,1);  % 生成在[0,16]之間均勻分布的隨機數組成的n行1列的向量構成x1
x2=unifrnd(0,8,n,1);  % 生成在[0,8]之間均勻分布的隨機數組成的n行1列的向量構成x2
fmin=+inf; % 初始化函數f的最小值為正無窮(后續只要找到一個比它小的我們就對其更新)
for i=1:n
    x = [x1(i), x2(i)];  %構造x向量, 這里千萬別寫成了:x =[x1, x2]
    if (3*x(1)+x(2)>9)  &  (x(1)+2*x(2)<16)     % 判斷是否滿足條件
        result = 2*(x(1)^2)+x(2)^2-x(1)*x(2)-8*x(1)-3*x(2);  % 如果滿足條件就計算函數值
        if  result  < fmin  % 如果這個函數值小於我們之前計算出來的最小值
            fmin = result;  % 那么就更新這個函數值為新的最小值
            X = x;  % 並且將此時的x1 x2 保存到相應的變量中
        end
    end
end
disp(strcat('蒙特卡羅模擬得到的最小值為',num2str(fmin)))
disp('最小值處x1 x2的取值為:')
disp(X)
toc %計算tic和toc中間部分的代碼的運行時間


%% (2)縮小范圍重新模擬得到更加精確的取值
clc,clear;
tic %計算tic和toc中間部分的代碼的運行時間
n=10000000; %生成的隨機數組數
x1=unifrnd(2,3,n,1);  % 生成在[2,3]之間均勻分布的隨機數組成的n行1列的向量構成x1
x2=unifrnd(2,3,n,1);  % 生成在[2,3]之間均勻分布的隨機數組成的n行1列的向量構成x2
fmin=+inf; % 初始化函數f的最小值為正無窮(后續只要找到一個比它小的我們就對其更新)
for i=1:n
    x = [x1(i), x2(i)];  %構造x向量, 這里千萬別寫成了:x =[x1, x2]
    if (3*x(1)+x(2)>9)  &  (x(1)+2*x(2)<16)     % 判斷是否滿足條件
        result = 2*(x(1)^2)+x(2)^2-x(1)*x(2)-8*x(1)-3*x(2);  % 如果滿足條件就計算函數值
        if  result  < fmin  % 如果這個函數值小於我們之前計算出來的最小值
            fmin = result;  % 那么就更新這個函數值為新的最小值
            X = x;  % 並且將此時的x1 x2 保存到相應的變量中
        end
    end
end
disp(strcat('蒙特卡羅模擬得到的最小值為',num2str(fmin)))
disp('最小值處x1 x2的取值為:')
disp(X)
toc %計算tic和toc中間部分的代碼的運行時間

作業2

​ 某設備上安裝有四只型號規格完全相同的電子管,已知電子管壽命(假定為整數)為1000h~2000h之間的均勻分布.當電子管損壞時有兩種維修方案,一是每次更換損壞的那一只;二是當其中一只損壞時四只同時更換.已知更換時間為換一只時需1h,4只同時換為2h.更換時機器因停止運轉每小時的損失為20元,又每只電子管價格10元,試用模擬方法決定哪一個方案經濟合理?

%% 選擇決策方案的模擬
% 某設備上安裝有四只型號規格完全相同的電子管,已知電子管壽命為1000--2000小時之間的均勻分布(假定為整數)。
% 當電子管損壞時有兩種維修方案,一是每次更換損壞的那一只;二是當其中一只損壞時四只同時更換。
% 已知更換時間為換一只時需1小時,4只同時換為2小時。
% 更換時機器因停止運轉每小時的損失為20元,又每只電子管價格10元,
% 試用模擬方法決定哪一個方案經濟合理?

%% (1)預備知識
% randi([a,b],m,n)  隨機生成m*n的矩陣,矩陣中的每個元素都是[a,b]中的隨機整數
randi([1, 5],3,2)
randi([1, 5])  % 不寫m*n代表只生成1個隨機數

% find函數的用法
% find函數的用法在第一期視頻:層次分析法那一節講過,我們當時找最大特征值的位置
a = [2 3 5 1 7 5];
find(a)  % 找到a中所有非0元素的位置
find(a == 5)  % 找到a中等於5的元素的位置
find(a == 5,1)  % 找到a中第一個等於5的元素的位置
find(a == min(a))   % 找到a中最小元素的位置

%% (2)代碼部分
clear;clc
T = 100000000;   % T表示模擬的總時間(單位為小時)
t = 0;   % 初始化當前時刻為0小時
c1 = 0; c2 = 0;  % 初始化兩種方案的總花費都為0

%%  方案一
life = randi([1000,2000],1,4);  % 隨機生成四個電子管的壽命,假設為整數
while t < T  % 只要現在的時刻沒有超過總時刻,就不斷循環下去
    result = min(life);  % 找出壽命最短的那一個電子管的壽命
    t = t+result+1;  % 現在的時間更改到有電子管損壞的時刻(加上1表示更換電子管需要花費的時間)
    c1 = c1 + 20 * 1 +10;  % 更新方案一的花費 
    k = find(life == result,1);   % 找到哪一個電子管是壞的
    life = life - result -1; % 更新所有電子管的壽命    
    life(k) = randi([1000,2000]);  % 把壞掉的那個電子管的壽命重置
end

%%  方案二
t = 0;   % 初始化當前時刻為0小時
while t < T  % 只要現在的時刻沒有超過總時刻,就不斷循環下去
    life = randi([1000,2000],1,4); % 隨機生成四個電子管的壽命,假設為整數
    result = min(life); % 找出壽命最小的那一個電子管的壽命
    t = t+result+2;  % 現在的時間更改到有電子管損壞的時刻(加上2表示更換所有電子管需要花費的時間)
    c2 =c2 + 20 * 2 +40;  % 更新方案二的花費 
end

%% 兩種方案的花費
c1
c2




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM