|
发表于 2012-6-26 12:57:00
|
显示全部楼层
Re:自己给自己出了一道题却解不开,求大神帮忙!
一、如果钥匙包和三个箱子是不可重复的。
当拿到三个钥匙包的时候,各种钥匙的数目是确定的了,分别为k=(k1,k2,k3);
当遇到了三个箱子的时候,各个箱子需要各种钥匙的数目也是固定的了,可以用一个矩阵来表示:
B=[n11 n12 n13
n21 n22 n23
n31 n32 n33]
其中每一行对应一个箱子需要各种钥匙的数目。
那么问题就转化成一个整数优化的问题:
设开启各个箱子的数目分别为 x=(x1,x2,x3)
目标函数为:
min Z=sum(x)
约束条件为:
xB<=k 且 x为自然数
求解整数规划一般用分支定界法,但是由于三个钥匙包中的钥匙至少可以开启0个箱子,最多开启3个箱子,完全可以用枚举的方法来求解(每个箱子的个数从0到3循环)。
另外:获得钥匙包的情况总共有C(6,3)=20种;遇到箱子的情况总共有C(6,3)=20种;而且
钥匙包和箱子包(三个算一个包)的对应情况有20×20=400种,用程序枚举也很快。
根据以上的思路,用matlab求解之。
子函数一,用于求获得各种钥匙和的情况集合
function KeySum=KeyNum(Key,k)
% k个钥匙宝所含各种钥匙和的情况
KeyIndex=combntns(1:size(Key,1),k);
n=size(KeyIndex,1);
KeySum=zeros(n,size(Key,2));
for i=1:n
KeySum(i, =sum(Key(KeyIndex(i,:),:));
end
子函数二,用于求遇到箱子的情况集合
function BoxSum=BoxNum(Box,k)
% 遇到k个箱子需要钥匙的所有情况
BoxIndex=combntns(1:size(Box,1),k);
n=size(BoxIndex,1);
BoxSum=zeros(k,size(Box,2),n);
for i=1:n
BoxSum(:,:,i)=Box(BoxIndex(i,:),:);
end
子函数三,枚举法求整数规划的最优解
function [Box,MaxBoxNum]=MaxBox(K,B)
% 简单的循环求开启箱子的最大个数
MaxBoxNum=0;
Box=[0 0 0];
for box_1=0:3
for box_2=0:3
for box_3=0:3
KeyNeed=B'*[box_1 box_2 box_3]';
BoxNum=box_1+box_2+box_3;
if KeyNeed(1)<=K(1) && KeyNeed(2)<=K(2) && KeyNeed(3)<=K(3)
if BoxNum>MaxBoxNum
MaxBoxNum=BoxNum;
Box=[box_1,box_2,box_3];
end
end
end
end
end
主函数:
clc;clear all;format long g;
Key=[1 1 0
1 0 1
0 1 1
2 0 0
0 2 0
0 0 2];
Box=[1 1 0
1 0 1
0 1 1
2 0 0
0 2 0
0 0 2];
K=KeyNum(Key,3);
B=BoxNum(Box,3);
S=0;
for k=1:20
for b=1:20
[~,MaxBoxNum]=MaxBox(K(k,:),B(:,:,b));
S=S+MaxBoxNum;
end
end
fprintf('平均可以开启 %g 个箱子。\n',S/400);
运行结果:
平均可以开启 2.19 个箱子。
开启箱子数目及对应的概率为:
0 1 2 3
3/400 63/400 189/400 29/80
二、如果钥匙包和三个箱子是可以重复的。
思路和上面相似,只不过求钥匙包情况集合以及三个箱子情况集合的方法稍有不同,但是也比较简单。虽然,由于可以重复,获得钥匙的数目情况与上面的情况不同,但是可以开启的箱子个数仍然是从0到3,即便如此为了保险起见,将搜索范围扩大到从0到6(经验证,两种搜索范围的结果是相同的)。下面仅罗列结果:
子函数一:
function CombIndex=Comb3(N)
% 从1:N中可重复得选择3个数的所有情况组合
CoIn_1=combntns(1:N,3);
CoIn_2=combntns(1:N,2);
CoIn_3=combntns(1:N,1);
CombIndex=[CoIn_1;[CoIn_2 CoIn_2(:,1)];[CoIn_2 CoIn_2(:,2)];[CoIn_3 CoIn_3 CoIn_3]];
子函数二:
function KeySum=KeyNum(Key)
KeyIndex=Comb3(size(Key,1));
n=size(KeyIndex,1);
KeySum=zeros(n,size(Key,2));
for i=1:n
KeySum(i,:)=sum(Key(KeyIndex(i,:),:));
end
子函数三:
function BoxSum=BoxNum(Box)
BoxIndex=Comb3(size(Box,1));
n=size(BoxIndex,1);
BoxSum=zeros(3,size(Box,2),n);
for i=1:n
BoxSum(:,:,i)=Box(BoxIndex(i,:),:);
end
子函数四:
function [Box,MaxBoxNum]=MaxBox(K,B)
% 简单的循环求开启箱子的最大个数
MaxBoxNum=0;
Box=[0 0 0];
for box_1=0:6
for box_2=0:6
for box_3=0:6
KeyNeed=B'*[box_1 box_2 box_3]';
BoxNum=box_1+box_2+box_3;
if KeyNeed(1)<=K(1) && KeyNeed(2)<=K(2) && KeyNeed(3)<=K(3)
if BoxNum>MaxBoxNum
MaxBoxNum=BoxNum;
Box=[box_1,box_2,box_3];
end
end
end
end
end
主函数:
clc;clear all;format long g;
Key=[1 1 0
1 0 1
0 1 1
2 0 0
0 2 0
0 0 2];
Box=[1 1 0
1 0 1
0 1 1
2 0 0
0 2 0
0 0 2];
K=KeyNum(Key);
B=BoxNum(Box);
j=1;S=zeros(1,size(K,1)*size(B,3));
for k=1:size(K,1)
for b=1:size(B,3)
[~,MaxBoxNum]=MaxBox(K(k,:),B(:,:,b));
S(j)=MaxBoxNum;
j=j+1;
end
end
fprintf('平均可以开启 %g 个箱子。\n',mean(S));
运行结果:
平均可以开启 1.65689 个箱子。
对应开启箱子个数的概率为:
0 1 2 3
64/449 166/631 95/244 57/278 |
|