在 PHP 中,如何找到所有 N 个个位数、非重复数字的总和达到给定总和的集合?

发布于 2024-08-31 08:28:55 字数 386 浏览 16 评论 0原文

假设我想找到所有 5 个个位数的非重复数字,加起来等于 30...我最终会得到 [9,8,7,5,1], [9,8,7 ,4,2]、[9,8,6,4,3]、[9,8,6,5,2]、[9,7,6,5,3] 和 [8,7,6, 5,4]。每组都包含 5 个不重复的数字,加起来等于 30,即给定的总和。

任何帮助将不胜感激。即使只是我使用的一个起点也会很棒。

我想出了一种方法,这似乎是一个很长的方法:获取所有唯一的 5 位数字(12345、12346、12347 等),将数字相加,然后看看它是否等于给定的总和(例如30)。如果是,则将其添加到可能的匹配集列表中。

我这样做是为了一个个人项目,这将帮助我解决数谜题,而不是一次真正解决整个问题。是的,这可能是作弊,但它......它并没有那么糟糕......:P

Let's say I want to find all sets of 5 single-digit, non-repeating numbers that add up to 30... I'd end up with [9,8,7,5,1], [9,8,7,4,2], [9,8,6,4,3], [9,8,6,5,2], [9,7,6,5,3], and [8,7,6,5,4]. Each of those sets contains 5 non-repeating digits that add up to 30, the given sum.

Any help would be greatly appreciated. Even just a starting point for me to use would be awesome.

I came up with one method, which seems like a long way of going about it: get all unique 5-digit numbers (12345, 12346, 12347, etc.), add up the digits, and see if it equals the given sum (e.g. 30). If it does, add it to the list of possible matching sets.

I'm doing this for a personal project, which will help me in solving Kakuro puzzles without actually solving the whole thing at once. Yeah, it may be cheating, but it's... it's not THAT bad... :P

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

一种简单的方法是将变量从 12345 增加到 98765,并且仅当它具有唯一数字且数字总和为 30 时才选择它:

for($i=12345;$i<98765;$i++) {
    $arr = preg_split('//',strval($i));
    if(count(array_unique($arr)) == count($arr) && array_sum($arr) == 30)
        echo $i."\n";
}

工作示例

A naive approach would be to increment a variable from 12345 till 98765 and to select it only if it has unique digits and sum of digits is 30:

for($i=12345;$i<98765;$i++) {
    $arr = preg_split('//',strval($i));
    if(count(array_unique($arr)) == count($arr) && array_sum($arr) == 30)
        echo $i."\n";
}

Working example

无声静候 2024-09-07 08:28:55
function sumOfDigits($num) {
    $str = "{$num}";
    $sum = 0;
    for ($i=0;$i<strlen($str);$i++) {
        $sum += (int)substr($str, $i, 1);
    }
    return $sum;
}

function hasDuplicateDigits($num) {
    $str = "{$num}";
    $pieces = array();
    for ($i=0;$i<strlen($str);$i++) {
        $pieces[] = substr($str, $i, 1);
    }
    return (count(array_unique($pieces)) != strlen($str));
}

// if you prefer the opposite function
function hasAllUniqueDigits($num) {
    return (!hasDuplicateDigits($num));
}

$numbers = range(10000, 99999);

foreach ($numbers as $num) {
    if ( !hasDuplicateDigits($num) && (sumOfDigits($num) == 30)) {
        print $num . "\n";
    }
}
function sumOfDigits($num) {
    $str = "{$num}";
    $sum = 0;
    for ($i=0;$i<strlen($str);$i++) {
        $sum += (int)substr($str, $i, 1);
    }
    return $sum;
}

function hasDuplicateDigits($num) {
    $str = "{$num}";
    $pieces = array();
    for ($i=0;$i<strlen($str);$i++) {
        $pieces[] = substr($str, $i, 1);
    }
    return (count(array_unique($pieces)) != strlen($str));
}

// if you prefer the opposite function
function hasAllUniqueDigits($num) {
    return (!hasDuplicateDigits($num));
}

$numbers = range(10000, 99999);

foreach ($numbers as $num) {
    if ( !hasDuplicateDigits($num) && (sumOfDigits($num) == 30)) {
        print $num . "\n";
    }
}
离不开的别离 2024-09-07 08:28:55

这可能足够快:

<?php

$digitCount = 5;
$sum = 30;

function getAnswer($b)
{
        $a = "";
        $i = 1;
        while ($b)
        {
                if ($b & 1) $a .= "$i ";

                $b >>= 1;
                ++$i;
        }
        return $a;
}

for ($b = 0; $b < 512; ++$b)
{
        $v = 0;
        $c = 0;
        $i = 1;

        $s = $b;
        while ($s)
        {
                if ($s & 1)
                {
                        if (++$c > $digitCount) continue 2;
                        $v += $i;
                }
                $s >>= 1;
                ++$i;
        }

        if ($c == $digitCount && $v == $sum)
        {
                echo getAnswer($b)."\n";
        }
}

?>

This is probably sufficiently fast:

<?php

$digitCount = 5;
$sum = 30;

function getAnswer($b)
{
        $a = "";
        $i = 1;
        while ($b)
        {
                if ($b & 1) $a .= "$i ";

                $b >>= 1;
                ++$i;
        }
        return $a;
}

for ($b = 0; $b < 512; ++$b)
{
        $v = 0;
        $c = 0;
        $i = 1;

        $s = $b;
        while ($s)
        {
                if ($s & 1)
                {
                        if (++$c > $digitCount) continue 2;
                        $v += $i;
                }
                $s >>= 1;
                ++$i;
        }

        if ($c == $digitCount && $v == $sum)
        {
                echo getAnswer($b)."\n";
        }
}

?>
又爬满兰若 2024-09-07 08:28:55

使用此处中的组合代码

foreach(new Combinations("123456789", 5) as $p)
    $r[array_sum(str_split($p))] .= "$p ";
print_r($r); 

结果

[15] => 12345 
[16] => 12346 
[17] => 12347 12356 
[18] => 12348 12357 12456 
[19] => 12349 12358 12367 12457 13456 
[20] => 12359 12368 12458 12467 13457 23456 
[21] => 12369 12378 12459 12468 12567 13458 13467 23457 
[22] => 12379 12469 12478 12568 13459 13468 13567 23458 23467 
[23] => 12389 12479 12569 12578 13469 13478 13568 14567 23459 23468 23567 
[24] => 12489 12579 12678 13479 13569 13578 14568 23469 23478 23568 24567 
[25] => 12589 12679 13489 13579 13678 14569 14578 23479 23569 23578 24568 34567 
[26] => 12689 13589 13679 14579 14678 23489 23579 23678 24569 24578 34568 
[27] => 12789 13689 14589 14679 15678 23589 23679 24579 24678 34569 34578 
[28] => 13789 14689 15679 23689 24589 24679 25678 34579 34678 
[29] => 14789 15689 23789 24689 25679 34589 34679 35678 
[30] => 15789 24789 25689 34689 35679 45678 
[31] => 16789 25789 34789 35689 45679 
[32] => 26789 35789 45689 
[33] => 36789 45789 
[34] => 46789 
[35] => 56789 

是不是很可爱?

Using Combinations code from here

foreach(new Combinations("123456789", 5) as $p)
    $r[array_sum(str_split($p))] .= "$p ";
print_r($r); 

result

[15] => 12345 
[16] => 12346 
[17] => 12347 12356 
[18] => 12348 12357 12456 
[19] => 12349 12358 12367 12457 13456 
[20] => 12359 12368 12458 12467 13457 23456 
[21] => 12369 12378 12459 12468 12567 13458 13467 23457 
[22] => 12379 12469 12478 12568 13459 13468 13567 23458 23467 
[23] => 12389 12479 12569 12578 13469 13478 13568 14567 23459 23468 23567 
[24] => 12489 12579 12678 13479 13569 13578 14568 23469 23478 23568 24567 
[25] => 12589 12679 13489 13579 13678 14569 14578 23479 23569 23578 24568 34567 
[26] => 12689 13589 13679 14579 14678 23489 23579 23678 24569 24578 34568 
[27] => 12789 13689 14589 14679 15678 23589 23679 24579 24678 34569 34578 
[28] => 13789 14689 15679 23689 24589 24679 25678 34579 34678 
[29] => 14789 15689 23789 24689 25679 34589 34679 35678 
[30] => 15789 24789 25689 34689 35679 45678 
[31] => 16789 25789 34789 35689 45679 
[32] => 26789 35789 45689 
[33] => 36789 45789 
[34] => 46789 
[35] => 56789 

isn't it cute?

浮光之海 2024-09-07 08:28:55

我知道有一些算法可以实现这一点,并且它们可能会由其他人提供,但是您可以进行一个快速简化:查找所有 4 个个位数加起来为 21-29 的集合(我假设您是不把 0 算作一个数字),只消除 30-(总和)是其中一个数字的那些。

如果我想更快地尝试一些东西,我会考虑从 45678 开始,通过在一个数字上加 1 并从另一个数字上减去 1 来逐步改变它。但不确定最终效果如何。

I know there are algorithms for this, and they will probably be provided by other people, but here's one quick simplification you can make: look for all sets of 4 single digits that add up to 21-29 (I'm assuming you're not counting 0 as a digit) and just eliminate the ones for which 30-(the sum) is one of the digits.

If I wanted to try something even quicker, I'd think about starting with 45678 and incrementally changing that by adding 1 to a digit and subtracting 1 from another digit. Not sure how well it'd work in the end, though.

累赘 2024-09-07 08:28:55

我相信这被称为子集和问题:

http://mathworld.wolfram.com/SubsetSumProblem.html

I believe this is known as the Subset Sum problem:

http://mathworld.wolfram.com/SubsetSumProblem.html

傲影 2024-09-07 08:28:55

让我们写 f(30,5,1) 作为问题的答案。 30 表示所需的总和,5 表示应添加到所需总和的位数,1 表示可接受的最小位数。在这种形式下,您可以递归地解决问题。例如,

f(30,5,b) = sum(i = 1..9) f(30-i,4,i+1)

我们正在有效地穷尽出现的最低值 i在您寻求的组合中。
如果您更仔细地考虑 i 的最大可能值(它不能太大,因为它是数字中的最小值),并添加一些适当的纾困条件,那么您将获得一个非常快速的解决方案。

Let's write f(30,5,1) for the answer to your problem. The 30 indicates the desired sum, the 5 indicates the number of digits which should add to the desired sum, and the 1 indicates the minimal acceptable digit. In this form, you can solve the problem recursively. For example,

f(30,5,b) = sum(i = 1..9) f(30-i,4,i+1)

We are effectively exhausting over the lowest value i occurring in the combination you seek.
If you think more carefully about the maximum possible value of i (it can't be too large since it's the minimum of the digits), and add some appropriate bail-out conditions, then you'll have a very fast solution.

我很OK 2024-09-07 08:28:55

打印数字之和形成一个包含 n 个数字的数组,其中没有重复的数字。例如
输入:[100, 213, 414, 555, 62, 321]

输出:596(即 213+62+321 )

Print sum of numbers form an array of n numbers having no duplicate digit in it. For example
Input: [100, 213, 414, 555, 62, 321]

Output: 596 ( i.e. 213+62+321 )

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文