Javascript JS中大集合组合置换比的快速计算方法

Javascript JS中大集合组合置换比的快速计算方法,javascript,arrays,algorithm,matlab,combinations,Javascript,Arrays,Algorithm,Matlab,Combinations,当遇到大量的数字时,试图用快速有效的方法计算比率。这个想法是一个带有数字的数组,例如框=[1,2,3,4],并将数组中的每个项目命名为1=A,2=B,3=C,4=D。然后使用数字调用步骤。我正在尝试为方框中的每个元素实现这一点,例如,第一个元素A只有3个步骤 在步骤1中,取A的值并将其除以框和 step 1 => 1/10 = 0.1 在第2步中,取组合BA、CA、DA,然后除以框总和,每次减去前一个值 => (2/10)(1/8) + (3/10)(1/7) + (4/10)(1

当遇到大量的数字时,试图用快速有效的方法计算比率。这个想法是一个带有数字的数组,例如=[1,2,3,4],并将数组中的每个项目命名为1=A,2=B,3=C,4=D。然后使用数字调用步骤。我正在尝试为方框中的每个元素实现这一点,例如,第一个元素A只有3个步骤

在步骤1中,取A的值并将其除以框和

step 1 => 1/10 = 0.1
在第2步中,取组合BA、CA、DA,然后除以框总和,每次减去前一个值

=> (2/10)(1/8) + (3/10)(1/7) + (4/10)(1/6) = 0.1345
在步骤3中,取组合BCA、BDA、CBA、CDA、DBA、DCA,然后除以框总和,每次减去之前的值

=> (2/10)(3/8)(1/5) + (2/10)(4/8)(1/4) + (3/10)(2/7)(1/5) + (3/10)(4/7)(1/3) + (4/10)(2/6)(1/4) + (4/10)(3/6)(1/3) = 0.2143
最后返回A=0.1+0.1345+0.2143=0.4488的所有步骤的总和 如果对长方体阵列B=0.7587、C=0.8702、D=0.9222中的所有元素执行相同的程序,以测试计算是否正确,则比率之和等于3,即使用的相同步数

如果增加框中的步骤和元素,则应按相同顺序进行所有组合。如果框大小为1000,并且框中的每个元素都有10个步骤,则此计算能否快速运行且不会耗尽内存

具有3步的数组长度4的递归公式 [A、B、C、D]

对于元素A

step 1 : A
step 2 : BA CA DA
step 3 : BCA  BDA  CBA  CDA  DBA  DCA
对于元素B

step 1 : B
step 2 : AB CB DB
step 3 : ACB  ADB  CAB  CDB  DAB  DCB
对于元素C

step 1 : C
step 2 : AC BC DC
step 3 : ABC  ADC  BAC  BDC  CAD  CBD
对于元素D

step 1 : D
step 2 : AD BD CD
step 3 : ABD  ACD  BAD  BCD  DAC  DBC
对于由5个元素和4个步骤组成的数组[A、B、C、D、E]

对于要素A:

   step 1: A

   step 2: BA CA DA EA 

   step 3: BCA BDA BEA CBA CDA CEA DBA DCA DEA EBA ECA EDA

   step 4:   
    BCDA
    BCEA
    BDCA
    BDEA
    BECA
    BEDA
    CBDA
    CBEA
    CDBA
    CDEA
    CEBA
    CEDA
    DBCA
    DBEA
    DCBA
    DCEA
    DEBA
    DECA
    EBCA
    EBDA
    ECBA
    ECDA
    EDBA
    EDCA
这里是我在Matlab代码中的尝试如果JS不可能,有没有办法改进Matlab代码

% sample code to test
userTickets = [1, 2, 3, 4];
users = [0, 0, 0, 0];
userCount = 4;
draws = 3;
for player = 1 :  length(users)
    userLuck = 0;
    for draw = 1 : prizes 
        userLuck = userLuck + cardCombo(player, userTickets, draw);
    end
    users(player) = userLuck;
end
total = sum(users);
****恩佩穆泰克

function [A, I] = npermutek(v,k)
narginchk(2,3);
nck = nchoosek(1:numel(v),k);
permutes = perms(1:k);
I = nck(:,permutes);
I = reshape(I,[],k);
I = sortrows(I,1:k);
A = v(I);
end
****卡片组合

function [result] = cardCombo(player, cards, draw)
    playerCards = cards(player);
    opponentCards = cards(setdiff(1:end,player));
    cardCount = sum(cards);
    if draw == 1
        result = playerCards/cardCount; 
    elseif draw == 2
        result = 0;  
        for n = 1 : length(opponentCards)
         result = result + ((opponentCards(n)/cardCount) * (playerCards/ (cardCount - opponentCards(n))));
        end   
    else
        combo = npermutek(opponentCards, draw -1);
        combWithPlayer = repmat(playerCards, size(combo,1),1);
        combo = [combo combWithPlayer];
        rowSize = size(combo, 1);
        colSize = size(combo,2);
        rowSum = 0;
        for row = 1 : rowSize
            rowMul = 1;
            sub = 0;
            for col = 1 : colSize
                num = combo(row, col);
                rowMul = rowMul * (num / (cardCount - sub));
                sub = sub + num;
            end
            rowSum = rowSum + rowMul;
        end
        result = rowSum;
    end    
end
原始方法 玩家p在排名正好
k
时获胜的概率为:

p(k) = sum_{a={A(k-1, N-1)}}( p(a) * p(P|a) )
在哪里

  • N
    是玩家的数量
  • {A(k-1,N-1)}
    N-1
  • p(a)
    来自
    {a(k-1,N-1)}的安排的概率
[1:k]

g(k) = sum_{i=1}^k p(i)
替代方法 另一种方法:赢得第一步或。。。或者,第10步与每一步都失败相反

也就是说,采用大小为k的所有排列方式,这样就不会出现p:
A(k,N-1)

虽然公式较短,但排列的大小较大(k而不是k-1),因此需要更多的时间。。。比原来的方法


在这一点上,优化可以集中于评估安排

我们可以尝试指数运算:

  • 计算所有
    {A(2,N-1)}
  • 然后通过重用
    {A(4,N-1)}
    (当没有两个字母相同时将它们连接起来)
  • 然后在没有两个字母相同的条件下连接
    {A(4,N-1)}x{A(4,N-1)}x{A(2,N-1)}
但是:注意
{A(4,N-1)}
的卡片是
999*998*997*996~=1e12
(我不敢使用这种笛卡尔乘积)

近似值 也许有更好的方法,但作为一种退路,可以简单地使用蒙特卡罗方法:

  • 使
    N
    simu
  • 绘制
    k
    随机数。如果在
    playerInterval
    中有抽签中的任何数字,则成功
  • 返回
    nbSuccess/N

避免调整数组的大小,考虑<代码>集合([1,2,3,…])< /> >并构造累积间隔

]0;1] U]1;1+2]U]3;3+3] ... etc

den==(n*(n+1)/2)
开始绘制,并检查着陆
i-th
间隔

如果
i!==玩家
,从集合中移除
i
,重新考虑新的累积间隔,从
den-i
依此类推,直到
k
(或成功)

功能A(k、v、cbk){
功能记录(手、深度){
如果(深度==k)返回cbk(手动)
对于(设i=0;i{
acc.res*=数量/acc.den
acc.den-=num
返回acc
},{den,res:1})
}
//原始方法
功能原点(盒子、播放器、步骤){
const-boxWithoutPlayer=box.slice(0)
无输出层的盒拼接(盒索引(播放器),1)
const total=box.reduce((s,x)=>s+x,0)
让s=玩家/总数
for(设步长=1;步长<步长;++步长){
A(步骤,无输出层的框,arr=>{
设{den,res}=p(arr,total)
s+=res*p([player],den).res
})
}
返回s
}
//替代方法
功能neg(盒子、播放器、步骤){
const-boxWithoutPlayer=box.slice(0)
无输出层的盒拼接(盒索引(播放器),1)
const total=box.reduce((s,x)=>s+x,0)
设s=0
A(步骤,无输出层的框,arr=>{
s+=p(arr,总计).res
})
返回1-s
}
//蒙特卡洛约
功能mc(盒子、播放器、步骤){
常数NSimu=1e5
让成功=0
//https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random
const getRandomInt=max=>Math.floor(Math.random()*Math.floor(max))
const total=box.reduce((s,x)=>s+x,0)
for(设i=0;idic[m]())
console.log('---')
}
main([…数组(6)].map((x,i)=>i+1),3,3,['orig','neg','mc'])
main([…数组(10)].map((x,i)=>i+1),8,7,['orig','neg','mc'])
//需要1000;900;10磅
g(k) = 1 - sum_{a={A(k, N-1)}} p(a)