游戏开发论坛

 找回密码
 立即注册
搜索
查看: 5946|回复: 11

[讨论] 自己给自己出了一道题却解不开,求大神帮忙!

[复制链接]

6

主题

37

帖子

42

积分

注册会员

Rank: 2

积分
42
发表于 2012-6-8 16:00:00 | 显示全部楼层 |阅读模式
有一个活动,会往场景中投放大量的钥匙包和宝箱
钥匙包可以开出三种不同类型的钥匙,一孔钥匙,二孔钥匙,三孔钥匙

获得钥匙几率分别如下:
         一孔钥匙  二孔钥匙  三孔钥匙
1/6几率      1         1         0
1/6几率      1         0         1
1/6几率      0         1         1
1/6几率      2         0         0
1/6几率      0         2         0
1/6几率      0         0         2

当玩家获得了钥匙后去开宝箱
每个宝箱都会需要不同类型钥匙,且需要数量也不同

需要钥匙几率分别如下:
         一孔钥匙  二孔钥匙  三孔钥匙
1/6几率      1         1         0
1/6几率      1         0         1
1/6几率      0         1         1
1/6几率      2         0         0
1/6几率      0         2         0
1/6几率      0         0         2


问题来了
当玩家获得三个钥匙包,刚好又碰到了三个宝箱
请问:玩家能够开启多少个宝箱(允许有小数)

0

主题

36

帖子

93

积分

注册会员

Rank: 2

积分
93
发表于 2012-6-24 17:37:00 | 显示全部楼层

Re:自己给自己出了一道题却解不开,求大神帮忙!

赶紧让程序写个模拟器,计算100万次.程序忙的话,你自己写吧

58

主题

1437

帖子

2207

积分

金牌会员

Rank: 6Rank: 6

积分
2207
发表于 2012-6-24 17:51:00 | 显示全部楼层

Re:自己给自己出了一道题却解不开,求大神帮忙!

这1/6机率哪来的,怎么定的?拍脑瘫定的吧?

0

主题

36

帖子

93

积分

注册会员

Rank: 2

积分
93
发表于 2012-6-24 18:58:00 | 显示全部楼层

Re:自己给自己出了一道题却解不开,求大神帮忙!

m=0;
for t=1:10000
a=0;
b=0;
c=0;
d=0;
e=0;
f=0;
g=0;
h=0;
k=0;
for i=1:3
    x=randint(1,1,[1 6]);
    switch x
        case 1
            a=a+1;
            b=b+1;
        case 2
            a=a+1;
            c=c+1;
        case 3
            b=b+1;
            c=c+1;
        case 4
            a=a+2;
        case 5
            b=b+2;
        case 6
            c=c+2;
    end
end

for j=1:3
    y=randint(1,1,[1 6]);
    switch y
        case 1
            d=d+1;
        case 2
            e=e+1;
        case 3
            f=f+1;
        case 4
            g=g+1;
        case 5
            h=h+1;
        case 6
            k=k+1;
    end
end

if a>0&b>0&d>0
    a=a-1;
    b=b-1;
    d=d-1;
    m=m+1;
end

if a>0&c>0&e>0
    a=a-1;
    c=c-a;
    e=e-1;
    m=m+1;
end

if b>0&c>0&f>0
    b=b-1;
    c=c-1;
    f=f-1;
    m=m+1;
end

if a>1&g>0
    a=a-2;
    g=g-1;
    m=m+1;
end

if b>1&h>0
    b=b-2;
    h=h-1;
    m=m+1;
end

if c>1&k>0
    c=c-2;
    k=k-1;
    m=m+1;
end
end
fprintf('%d\n',m);
这个算法不太准,主要是开箱子的顺序算法用我这种matlab水平写不出来了。就算如此,但也应该接近实际结果了,1万次的结果是能开1.5个箱子,算上10-20%的补偿系数,大概1.7~1.8之间

0

主题

36

帖子

93

积分

注册会员

Rank: 2

积分
93
发表于 2012-6-24 19:32:00 | 显示全部楼层

Re:自己给自己出了一道题却解不开,求大神帮忙!

关于这道题,如何设计算法,求指导

20

主题

903

帖子

977

积分

高级会员

Rank: 4

积分
977
QQ
发表于 2012-6-25 16:33:00 | 显示全部楼层

Re: Re:自己给自己出了一道题却解不开,求大神帮忙!

xyx1985feng: Re:自己给自己出了一道题却解不开,求大神帮忙!

m=0;
for t=1:10000
a=0;
b=0;
c=0;
d=0;
e=0;
f=0;
g=0;
h=0;
k=0;
for i=1:3
    x=randint(...


完全没看明白你后面来一长串的if是干嘛。。。看起来思路很奇怪
3次随机算出3个钥匙包得到所有的钥匙之后,应该在3次随机箱子的时候分别比对箱子是不是能开,能开则扣掉钥匙,不能开则不扣钥匙
-------------------------------------------
修正一下,需要先随机分别得到3个箱子,然后按照不同顺序(6种顺序)分别对比箱子能不能开,取其中的最大值
-------------------------------------------

实际上,这道题,可以简化为:
有3种钥匙,每个钥匙包里面有2把,种类随机,机会均等
宝箱需要2个钥匙(也是以上3种钥匙),所需要的钥匙种类同样完全随机,机会均等


按这个来看,平均大约能开2次

5

主题

101

帖子

1723

积分

金牌会员

Rank: 6Rank: 6

积分
1723
发表于 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   

20

主题

903

帖子

977

积分

高级会员

Rank: 4

积分
977
QQ
发表于 2012-6-26 15:04:00 | 显示全部楼层

Re:自己给自己出了一道题却解不开,求大神帮忙!

全部的组合里面只有3种情况开0个箱子??
似乎和感觉不符

例如:

钥匙
[2,0,0]
[2,0,0]
[2,0,0]
箱子
[0,0,2]
[0,0,2]
[0,0,2]
后面两个数的互换,情况就有4种了

再加上还有
箱子
[1,0,1]
[0,0,2]
[0,0,2]
这种情况也有6种

beer的思路应该没有问题,那么是算法错了?

5

主题

101

帖子

1723

积分

金牌会员

Rank: 6Rank: 6

积分
1723
发表于 2012-6-26 21:01:00 | 显示全部楼层

Re: Re:自己给自己出了一道题却解不开,求大神帮忙!

teeth_yuanli: Re:自己给自己出了一道题却解不开,求大神帮忙!

全部的组合里面只有3种情况开0个箱子??
似乎和感觉不符

例如:

钥匙
[2,0,0]
[2,0,0]
[2,0,0]
...


7L的teeth兄的指误是对的。但是问题出在哪里呢?
————因为我算的是钥匙包和三个箱子都没有重复的情况。

如果两者都有重复,那就是[C(6,3)+C(6,1)×C(5,1)+C(6,1)]^2=56^2=3136种情况。

我来修正一下,但是会保留原来的“错误”解答,算是一个情况吧(虽然出题者不是这个意思)

20

主题

903

帖子

977

积分

高级会员

Rank: 4

积分
977
QQ
发表于 2012-6-27 10:44:00 | 显示全部楼层

Re:自己给自己出了一道题却解不开,求大神帮忙!

啤酒兔兄。。。其实我怀疑的错误并不是你想的那个

因为钥匙包和箱子的组合都不需要考虑次序,所以组合次数确实是C(6,3)*C(6,3)没有错
但是在这种情况,我在7L所给出的例子很明显超过了3个,所以怀疑是中间整数规划求解的那一段有问题

我看不懂语言,不知道那段程序是怎么处理的,但是因为用已有的钥匙“开箱子”的次序不同,会造成不同的结果,所以我之前才提出开箱子的次序要循环求最大值的
不知道这个建议您是否考虑一下?

---------------------
好像是我弄错了,,sorry
---------------------
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

作品发布|文章投稿|广告合作|关于本站|游戏开发论坛 ( 闽ICP备17032699号-3 )

GMT+8, 2025-6-29 05:14

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表