【问题标题】:How to group N items?如何对 N 个项目进行分组?
【发布时间】:2011-03-22 18:59:11
【问题描述】:

我正在研究一个集合分区问题,需要一种方法来定义无序存储桶大小的所有组合。给定 N 个元素和恰好 M 个组,找到每个组大小的组合,使得组大小的总和为 N。注意:桶的大小不能为 0。

例如,假设需要将 6 件物品放在 3 个桶中。我正在寻找的解决方案是:

([1,2,3],[1,1,4],[2,2,2])

为了平等地映射这些,我使用如下映射函数:

@grouping = map { int( ($items + $_) / $groups ) } 0 .. $groups-1;

为了获得所有组合,我正在考虑某种递归函数,其中每个级别的递归 N 找到数组中元素 N 的可能值。每个级别可以插入的合格值是 >= previousLevel。这就是我的想法,但必须有更好的方法来做到这一点......

sub getList($$@){
    my $itemCount = shift;
    my $groupCount = shift;
    my @currentArray = @_;
    my $positionToFill= @currentArray;
    if($positionToFill == 0){
        my $minValue = 1;
    }
    else{
        my $minValue = currentArray[$positionToFill-1];
    }
    my $currentSum = sum(@currentArray);
    return undef if $currentSum + $minValue >= $items;

    my @possibleCombinations = ();
    for(my $i = $minValue; $i < $items - $currentSum; $i++){
        $currentArray[$positionToFill] = $i;
        if($positionToFill == $groupCount-1){
            push(@possibleCombinations, \@currentArray)
        }
        else{
            push(@possibleCombinations, getList($itemCount, $groupCount, @currentArray);
        }                        
    }
    return @currentArray;
}

【问题讨论】:

  • 您需要告诉我们您目前的情况,以及您的具体问题是什么。
  • 创建所有组合,然后过滤掉不符合求和条件的组合。
  • @Ether:适用于 6 但不能很好地扩展
  • @ysth:当然,但是 OP 没有说性能是优先事项,也没有提到存储桶可能有多大。目前还不清楚家庭作业是否需要更优化的解决方案。此外,一个低效的解决方案通常总比没有好,编写它可以让我们深入了解如何改进它。

标签: perl set


【解决方案1】:

要将 N 个项目分成 M 个组,最终您需要一个递归函数,将 N-1 个(或更少)个项目分成 M-1 个组。

sub partition {
    # @results is a list of array references, the part of the partitions
    # created in previous iterations
    my ($N, $M, @results) = @_;

    if ($M == 1) {
        # only one group. All elements must go in this group.
        return map [ sort {$a <=> $b} @$_, $N ], @results;
    }

    # otherwise, put from 1 to $N/$M items in the next group,
    # and invoke this function recursively
    my @new_results = ();
    for (my $n = 1; $n <= $N/$M; $n++) {
        push @new_results, partition($N-$n, $M-1,
                                map [ @$_, $n ] @results);
    }
    return @new_results;
}

并通过类似的调用开始该过程

@all_partitions = partition(6, 3, []);    #  [] = list with one ref to an empty array

此方法会产生一些您必须过滤掉的重复项,但总体而言它会非常有效。

【讨论】:

  • 如果您还传递了最大值,则不重复。
猜你喜欢
  • 2012-05-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-09-24
  • 1970-01-01
  • 1970-01-01
  • 2013-03-12
相关资源
最近更新 更多