以下题目是来自微信公众号数学建模清风老师的题目
以下是个人结合在微信公众号上学到的知识去做的,若有不正确或不足之处,欢迎指正!
Q1.A是一个矩阵,A(:)可以按照列方向的顺序(线性索引)将A中每个元素输出为一个向量,请问怎样按照行方向的顺序输出A中的所有元素。
解:使用A(:)后是线性索引,故想要得到以上结果通过观察,先取转置,在使用A(:)就可以了
A=[1 4 2;3 6 8];
B=A';
B(:)'
ans =
1 4 2 3 6 8
Q2.利用MATLAB模拟随机丢一枚骰子N次,骰子有均匀的六个面。
解:大家自行去查一下“伯努利大数定律”,以下只给代码
N=6000;
A=randi(6,1,N);
ind=find(A==6);
n=length(ind)
p=n/N
bias=abs(p-1/6)
n =
981
p =
0.1635
bias =
0.0032
Q5.MATLAB中有一个非常有用的函数:randperm函数,它能够将一个数字序列进行随机打乱。它有两种最为常见的用法:
用法1:randperm(n)可以将向量1:n中元素的顺序随机打乱,生成一个长度仍为n的新向量,因此所有可能出现的情况共n!种(全排列)。例如,当你运行randperm(4)时,你可能得到[1 4 3 2],也可能得到[3 2 4 1]。
用法2:randperm(n,k)表示从打乱的1:n序列中随机的选择k个数出来,显然这k个数都不相同,且k要小于等于n。例如,当你运行randperm(10,3)时,你可能得到[5 1 10],也可能得到[6 5 8]。
请回答下面的问题:
(1)根据上面的介绍,请你在MATLAB中测试randperm函数的功能。特别地,如果n是负数或者小数会出现怎样的情况?如果k大于n会出现怎样的情况?
解:话不多说,直接看
randperm(10,-2)
错误使用 randperm
输入必须为非负标量整数。
randperm(10,2.5)
错误使用 randperm
输入必须为非负标量整数。
randperm(10,11)
错误使用 randperm
K 必须小于或等于 N。
(2)假设一个商品推销员要去10个城市推销商品,该推销员随机从一个城市出发,需要经过其他所有城市后,回到出发城市(中途经过的城市不重复),请你为该推销员随机的生成一条路线。为了方便,这10个城市就用数字1至10表示
解:
randperm(10)
ans =
9 8 3 10 1 6 5 2 7 4
(3)完成下列场景中的这段程序:假设你是一名高数老师,你正在给同学们讲不定积分的计算。这时候你的PPT上出现了你备课时准备的4道练习题,你需要随机的抽取四名幸运同学来黑板上进行计算。已知你的班上共有50名同学,他们的学号分别是2021001至2021050,你在MATLAB中运行了你写的这个程序,0.1s后这四名同学的学号在MATLAB中被随机的输出出来。
解:
A=randperm(50,4);
B=2021000;
B+A
ans =
2021049 2021026 2021047 2021045
(4)假设某公司在年会上设置了抽奖环节。主办方准备了一个抽奖用的不透明盒子,盒子内有10张奖券,其面值分别为[1 25 10 20 50 100 200 500 1000],每名员工从中随机的抽取3张,将这3张奖券的面值相加就是最终获得的红包奖励。请你设计一个程序,模拟清风老师在该抽奖环节中抽取一次能获得的红包金额。
解:上面这个向量[1 25 10 20 50 100 200 500 1000]只有9个元素,不知道我有没有理解错。然后我就在这个向量的第一个位置加了一个元素0,相当于1你运气不好,抽到谢谢惠顾了哈哈。不过意思在就OK了。我们把10张卷的面值分别用1~10来代替,然后将随机抽到的再对应奖券的面值就OK了。
A=[0 1 25 10 20 50 100 200 500 1000];
disp('抽到的序号为:')
B=randperm(10,3)
for i=1:3
k(i)=A(B(i));
end
disp('抽到的3张卷的面值为:')
k
disp('抽到兑换的红包奖励为:')
sum(k)
抽到的序号为:
B =
8 10 3
抽到的3张卷的面值为:
k =
200 1000 25
抽到兑换的红包奖励为:
ans =
1225
(5)一副扑克牌有54张,其中大王和小王各一张,A,2,3,4,5,6,7,8,9,10,J,Q,K各有4张。假设我们不考虑桃杏梅方这四种花色,请你设计一个发牌程序,为地主发20张牌,两个农民各发17张牌。为了方便,A,2,3,4,5,6,7,8,9,10,J,Q,K分别用数字1至13代替,小王用14代替,大王用15代替。
解:这个题对我们初学者还是有一点点难度的,不过难度不大。首先我们要知道这边牌是随机的。且每张牌发出去后就不能再有了(也就是不重复)。但是不能直接用randperm(54,20)、randperm(5,17)、randperm(54,17)。因为这样生成出来会有重复。所以我们可以把1~54分成5个部分 ,即第一部分为1–13,第二部分为14,15,(即大王小王),接下来是16~28、29–41、42–54,你也可以理解为牌的花色。
数字 | 数字代表的牌 | 花色 |
---|---|---|
1–13 | A 1 2…J Q K | 黑桃 |
14–15 | 小王、大王 | |
16–28 | A 1 2…J Q K | 梅花 |
29–41 | A 1 2…J Q K | 方块 |
42–54 | A 1 2…J Q K | 红桃 |
- 首先使用randperm(54,20),得到1–54的20个乱序的数,即地主的牌的数字,然后把大于数字15的化为1–15内,地主的牌就得到了。
- 接下来是第一个农民的牌,我们已经在54个数中取出了20个,那么我们使用R=setdiif(K,dz) 函数取差集,也就是说1–54个数中哪些没被地主取走。剩下34个数字,取17个数,我们使用nm1=randperm(34,17) ,得到1–34的17个随机乱序的数,再将这17个数的位置索引对应着取过差集的R,即得到第一家农民的牌的数字(在1–54之间的数字),再把大于数字15的化为1–15内,就得到第一家地主的牌了。
- 直接用nm2=setdiff(R,nm11),即剩下的1–54中的17个数字就是第二家农民的的牌的数字,然后直接把大于数字15的化为1–15内,第二家农民的牌也得到了。代码如下:
clear,clc
K=1:54;
dz=randperm(54,20); %地主在54中随机选出来的个牌
%%
%转化为1~15个数之间
for h=1:length(dz);
if dz(h)<16 ; %标号在1~15
dz1(h)=dz(h);
elseif dz(h)>15&dz(h)<29 ; %标号在16~28
dz1(h)=dz(h)-15;
elseif dz(h)>28&dz(h)<42 ; %标号在29~41
dz1(h)=dz(h)-28;
else dz(h)>41&dz(h)<55 ; %标号在42~54
dz1(h)=dz(h)-41;
end
end
disp('地主的牌为:')
dz1
R=setdiff(K,dz); %去掉地主取到的标号
k1=1:34;
nm1=randperm(34,17); %第一家在剩下的34张中随机分配到的17张
%%
%这里是把在1~34选到的对应到剩下的牌的标号
for j=1:length(nm1);
nm11(j)=R(nm1(j));
end
nm11; %第一家农民随机在54张中分配到的的17张
%%
%转化为1~15个数之间
for h=1:length(nm11);
if nm11(h)<16;
nm111(h)=nm11(h);
elseif nm11(h)>15&nm11(h)<29;
nm111(h)=nm11(h)-15;
elseif nm11(h)>28&nm11(h)<42;
nm111(h)=nm11(h)-28;
else nm11(h)>41&nm11(h)<55;
nm111(h)=nm11(h)-41;
end
end
disp('第一个农民的牌为:')
nm111
%%
nm2=setdiff(R,nm11); %54张随机分配给地主家20张,第一家农民17张后剩下的17张的原始标号
%转化为1~15个数之间
for h=1:length(nm2);
if nm2(h)<16;
nm22(h)=nm2(h);
elseif nm2(h)>15&nm2(h)<29;
nm22(h)=nm2(h)-15;
elseif nm2(h)>28&nm2(h)<42;
nm22(h)=nm2(h)-28;
elseif nm2(h)>41&nm2(h)<55;
nm22(h)=nm2(h)-41;
end
end
disp('第二家农民的牌为:')
nm22
%%
%下面相当于把牌给排序了的
disp('排序后的牌:')
dizhu=sort(dz1) %地主家排序后的牌
nonmin1=sort(nm111) %第一家农民排序后的牌
nonmin2=sort(nm22) %第二家农民排序后的牌
结果如下(注意:每一次运行的结果都会不一样,即相当于重新洗牌发牌)