PHP排列组合算法

  • 其他
  • 2022-03-29
  • 740 已阅读
  • 作者: song5198038_1
  • 来源: 网络
简介今遇到一个小学数学题, 各位数字互不相同,且能被自身每个数字整除的最大五位数是多少, 想来想去只有各种试, 后面绝对麻烦, 就想着用代码来直接试, 就百度了一个排列组合的算法.

今遇到一个小学数学题, "各位数字互不相同,且能被自身每个数字整除的最大五位数是多少", 想来想去只有各种试, 后面绝对麻烦, 就想着用代码来直接试, 就百度了一个排列组合的算法.

1. 符合题干的整数, 百度得以下结论

若一个整数的末位是0、2、4、6或8,则这个数能被2整除。   
若一个整数的数字和能被3整除,则这个整数能被3整除   
若一个整数的末尾两位数能被4整除,则这个数能被4整除   
若一个整数的末位是0或5,则这个数能被5整除   
若一个整数能被2和3整除,则这个数能被6整除   
若一个整数的个位数字截去,再从余下的数中,减去个位数的2倍,如果差是7的倍数,则原数能被7整除。如果差太大或心算不易看出是否7的倍数,就需要继续上述「截尾、倍大、相减、验差」的过程,直到能清楚判断为止。例如,判断133是否7的倍数的过程如下:13-3×2=7,所以133是7的倍数;又例如判断6139是否7的倍数的过程如下:613-9×2=595 , 59-5×2=49,所以6139是7的倍数,余类推   
若一个整数的末尾三位数能被8整除,则这个数能被8整除   
若一个整数的数字和能被9整除,则者个整数能被9整除   
若一个整数末位时0,则这个数能被10整除

所以N是一个各位数字互不相等的自然数, 即N这个数可能是有0,1,2,3,4,5,6,7,8,9,0这几个数中的数字组成。且它能被它的每个数字整除。那么N这个数字中不能含有0,因为0不能作除数。由于N中没有0,那么5和偶数(2,3,6,8)不能同时存在。所以N中没有5。则N这个数字可以由含有1,2,3,4,6,7,8,9这些数字中的数字组成。又因为1+2+3+4+6+7+8+9=40,那么1,2,3,4,6,7,8,9这8个数字组成的数不能被9整除。那么要使N能被9整除,且保证N最大,那么就去掉数字4。则N由1,2,3,6,7,8,9组成。要使N能被7整除,则N这个整数的个位数字截去,再从余下的数中,减去个位数的2倍,如果差是7的倍数,则原数能被7整除。且N要被8整除。那么最后一位必须要为偶数。那么最后一位只能为2、6、8中的一位。

所以符合题目要求的是 1,2,3,6,7,8,9

2. 进行排列组合, 计算符合要求的数字组合

以下是度娘到的来自 CSDN  song5198038_1 的<PHP排列组合算法>

<?php
// 阶乘
function factorial($n) {
    return array_product(range(1, $n));
}
// 排列数
function A($n, $m) {
    return factorial($n)/factorial($n-$m);
}
// 组合数
function C($n, $m) {
    return A($n, $m)/factorial($m);
}
// 排列
function arrangement($a, $m) {
    $r = array();
    $n = count($a);
    if ($m <= 0 || $m > $n) {
        return $r;
    }
    for ($i=0; $i<$n; $i++) {
        $b = $a;
        $t = array_splice($b, $i, 1);
        if ($m == 1) {
            $r[] = $t;
        } else {
            $c = arrangement($b, $m-1);
            foreach ($c as $v) {
                $r[] = array_merge($t, $v);
            }
        }
    }
    return $r;
}

// 组合
function combination($a, $m) {
    $r = array();
    $n = count($a);
    if ($m <= 0 || $m > $n) {
        return $r;
    }
    for ($i=0; $i<$n; $i++) {
        $t = array($a[$i]);
        if ($m == 1) {
            $r[] = $t;
        } else {
            $b = array_slice($a, $i+1);
            $c = combination($b, $m-1);
            foreach ($c as $v) {
                $r[] = array_merge($t, $v);
            }
        }
    }
    return $r;
}
// ====== 测试 ======
$a = array("A", "B", "C", "D");
$r = arrangement($a, 2);
var_dump($r);
$r = A(4, 2);
echo $r."n";
$r = combination($a, 2);
var_dump($r);
$r = C(4, 2);
echo $r."n";

 

根据算法列出符合要求的组合, 并求最大值

<?php
    $res = arrangement($arr, 5);
    $nums = [];
    foreach ($res as $value) {
        $number = 0;
        foreach ($value as $key => $val) {
            $number += $val * pow(10, $key);
        }
        $nums[] = $number;
    }
    var_dump(count($nums));
    $nm = [];
    foreach ($nums as $value) {
        if ($value % 2 != 0) {
            continue;
        } else {
            $sval = strval($value);
            $sarr = str_split($sval);
            $ns = 0;
            foreach ($sarr as $val) {
                // echo $value . " % " . intval($val) . "=" . ($value % intval($val))."n";
                $ns += $value % intval($val);
            }
            if ($ns == 0) {
                $nm[] = $value;
            }
        }
    }
    var_dump(count($nm)); // 28
    var_dump($nm);  // [.....]
    var_dump(max($nm)); // 98136

 

3.  其他解决题目思路 
首先数字各不相同,且要求最大,则可以考虑万位和千位是98  
其次这个数是9的倍数,看数字之和,8的倍数看后三位,那么可以枚举8的倍数 
如果这个数是9的倍数,前两位的数字之和是17,那么后三位数字之和可能是1,10,19…. 
剩下的1,2,3,6,7组合最大的三位数是16, 最小为6, 那么这三位数字和应该是 10, 很明显这三个数为 1,3,6 
那么这个五位数就有两个可能98136, 98316(尾数必须为偶数). 代入计算符合要求的是 98136

 

很赞哦! ( 1 )