Javascript JS中大集合组合置换比的快速计算方法
当遇到大量的数字时,试图用快速有效的方法计算比率。这个想法是一个带有数字的数组,例如框=[1,2,3,4],并将数组中的每个项目命名为1=A,2=B,3=C,4=D。然后使用数字调用步骤。我正在尝试为方框中的每个元素实现这一点,例如,第一个元素A只有3个步骤 在步骤1中,取A的值并将其除以框和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
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
(我不敢使用这种笛卡尔乘积)
近似值
也许有更好的方法,但作为一种退路,可以简单地使用蒙特卡罗方法:
- 使
simuN
- 绘制
随机数。如果在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)