php怎么求阶乘_php-计算置换的阶乘等级(N选择K)

我最近了解了CNS和FNS,并且由于它们对我来说是如此优雅,因此我决定尝试并实现使用这些技术生成组合和置换的方法.我完成了将n个选择k组合转换为CSN等级的方法,反之亦然,但是我正在敲打墙壁,尝试对n个选择k(唯一)排列进行同样的操作.

多亏了@Joshua,我才可以使用未排序(从FNS到置换)的方法:

function Pr_Unrank($n, $k, $rank) { // rank starts at 1

if ($n >= $k) {

if (($rank > 0) && ($rank <= Pr($n, $k))) {

$rank--;

$result = array();

$factoriadic = array();

for ($i = 1; $i <= ($n - $k); ++$i) {

$rank *= $i;

}

for ($j = 1; $j <= $n; ++$j) {

$factoriadic[$n - $j] = ($rank % $j) + 1; $rank /= $j;

}

for ($i = $n - 1; $i >= 0; --$i) {

$result[$i] = $factoriadic[$i];

for ($j = $i + 1; $j < $n; ++$j) {

if ($result[$j] >= $result[$i]) {

++$result[$j];

}

}

}

return array_reverse(array_slice($result, 0 - $k));

}

}

return false;

}

这是我当前尝试进行排名(向FNS排列)的方法:

function Pr_Rank($n, $k, $permutation) {

if ($n >= $k) {

$result = range(1, $n);

$factoriadic = array();

foreach ($permutation as $key => $value) {

$factoriadic[$k - $key - 1] = array_search($value, $result);

array_splice($result, $factoriadic[$k - $key - 1], 1);

}

$result = 1;

foreach (array_filter($factoriadic) as $key => $value) {

$result += F($key) * $value;

}

return $result;

}

return false;

}

这些是我正在使用的辅助函数:

function F($n) { // Factorial

return array_product(range($n, 1));

}

function Pr($n, $k) { // Permutations (without Repetitions)

return array_product(range($n - $k + 1, $n));

}

问题是,仅当n = k(demo)时,Pr_Rank()方法才返回正确的等级:

var_dump(Pr_Rank(5, 2, Pr_Unrank(5, 2, 10))); // 3, should be 10

var_dump(Pr_Rank(5, 3, Pr_Unrank(5, 3, 10))); // 4, should be 10

var_dump(Pr_Rank(5, 5, Pr_Unrank(5, 5, 10))); // 10, it's correct

我使用上面链接的Wikipedia文章和this MSDN article进行了指导,我知道他们都不打算考虑k大小的子集,但是我完全不知道这种逻辑是什么样的…

我还尝试了谷歌搜索并搜索现有问题/答案,但尚未找到任何相关内容.

解决方法:

睡个好觉后,笔& amp;的一点帮助纸,我想通了.如果有人感兴趣:

例如,第42个5选择3排列是4-2-5,但是如果查看Pr_Unrank(),调用array_slice()的话,您会注意到实际排列(按照字典顺序)实际上是4-2 -5 [-1-3],最后两个元素将被舍弃,因此最终只能得到k个元素.

这对于计算阶乘(3-1-2 [-0-0])的小数表示非常重要:

> 4-2-5 =(2!* 3)(1!* 1)(0!* 2)= 9

> 4-2-5-1-3 =(4!* 3)(3!* 1)(2!* 2)(1!* 0)(0!* 0)= 82

不过,82不是正确的答案.要获得它,我们必须将其除以以下结果:

> Pr(5,5)/ Pr(5,3)(=)(5-3)! = 120/60 = 2

所以82/2是41,我所要做的就是加1以使排名从1开始.

Array // 5 choose 3 permutations

(

[1] => 1-2-3

[2] => 1-2-4

[3] => 1-2-5

[4] => 1-3-2

[5] => 1-3-4

[6] => 1-3-5

[7] => 1-4-2

[8] => 1-4-3

[9] => 1-4-5

[10] => 1-5-2

[11] => 1-5-3

[12] => 1-5-4

[13] => 2-1-3

[14] => 2-1-4

[15] => 2-1-5

[16] => 2-3-1

[17] => 2-3-4

[18] => 2-3-5

[19] => 2-4-1

[20] => 2-4-3

[21] => 2-4-5

[22] => 2-5-1

[23] => 2-5-3

[24] => 2-5-4

[25] => 3-1-2

[26] => 3-1-4

[27] => 3-1-5

[28] => 3-2-1

[29] => 3-2-4

[30] => 3-2-5

[31] => 3-4-1

[32] => 3-4-2

[33] => 3-4-5

[34] => 3-5-1

[35] => 3-5-2

[36] => 3-5-4

[37] => 4-1-2

[38] => 4-1-3

[39] => 4-1-5

[40] => 4-2-1

[41] => 4-2-3

[42] => 4-2-5

[43] => 4-3-1

[44] => 4-3-2

[45] => 4-3-5

[46] => 4-5-1

[47] => 4-5-2

[48] => 4-5-3

[49] => 5-1-2

[50] => 5-1-3

[51] => 5-1-4

[52] => 5-2-1

[53] => 5-2-3

[54] => 5-2-4

[55] => 5-3-1

[56] => 5-3-2

[57] => 5-3-4

[58] => 5-4-1

[59] => 5-4-2

[60] => 5-4-3

)

标签:permutation,combinatorics,base-conversion,php,math

来源: https://codeday.me/bug/20191201/2078776.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值