蒙特卡洛思想

本文介绍了蒙特卡洛思想,包括蒲丰投针实验、三门问题、排队问题和有约束的非线性规划,展示了如何通过随机抽样估算复杂问题的解决方案。此外,还涉及导弹追踪离散化和书店买书的实例,展示了算法在实际场景中的应用。
摘要由CSDN通过智能技术生成

算法思想

本质就是通过类似抽样调查的方法对于未知量进行判断结果,主要针对离散问题的仿真,有时可以实现连续性问题向离散型问题的转化,进而用蒙特卡洛进行估计

蒲丰投针

l =  0.520;    			 % 针的长度(任意给的)
a = 1.314;    			% 平行线的宽度(大于针的长度l即可)
n = 1000;    			% 做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)])
import math
import numpy as np
import matplotlib.pyplot as plt
from scipy import stats
from random import *
import warnings
warnings.filterwarnings("ignore")
L = 1
A = 2
num = 100000
res = 0
x = np.random.rand(num) * A / 2
phi = np.random.rand(num) * np.pi
fig=plt.figure()
ax=fig.add_subplot(111)
for i in range(0, num):
    if x[i] <= L / 2 * math.sin(phi[i]):
        res = res + 1
        ax.scatter(phi[i],x[i],c="r")
p = res / num
my_pi = (2 * L) / (A * p)
print(my_pi)
ax.set_xlim([0,math.pi])
ax.set_ylim([0,A/2])
plt.show()

在这里插入图片描述

三门问题

all=10000;
change=0;
notchange=0;
for i = 1:all
    r=randi([1,3]);
    tr=randi([1,3]);
    if r==tr
        notchange=notchange+1;
    else
        change=change+1;
    end
end
disp(["不改变:",notchange/all]);
disp(["改变:",change/all])

排队问题

在这里插入图片描述

arrive(1)=exprnd(10);
start(1)=arrive(1);
over(1)=normrnd(10,2)+start(1);
i=2;
timeSum=0;
while true
    arrive(i)=arrive(i-1)+exprnd(10);
    start(i)=max(arrive(i),over(i-1));
    if start(i)>480
        break
    end
    timeSum=timeSum+(start(i)-arrive(i));
    thisTime=normrnd(10,2);
    if thisTime<1
        over(i)=start(i)+1;
    else
        over(i)=start(i)+thisTime;
    end
    i=i+1;
end
disp(["一天共有"+num2str(i-1)+"人"])
disp(["平均时间"+num2str(timeSum/i)])

有约束的非线性规划问题

在这里插入图片描述

n=100000;
x_2=unifrnd(10,20,n,1);
x_1=x_2+10;
x_3=unifrnd(-10,16,n,1);     %通过两个不等式推出来的范围
res=-inf;
resX=0;
for i = 1:n
    X=[x_1(i),x_2(i),x_3(i)];
    if (-X(1)+2*X(2)+2*X(3)>=0) & (X(1)+2*X(2)+2*X(3)<=72)
        if X(1)*X(2)*X(3)>res
            res=X(1)*X(2)*X(3);
            resX=X;
        end
    end
end
disp(res);
disp(resX)

书店买书

在这里插入图片描述

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 = 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

导弹追踪离散化

在这里插入图片描述
在这里插入图片描述

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

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

「 25' h 」

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值