以所有独特方式在桶之间分配/分配和的算法

时间:2013-03-13 14:33:23

标签: algorithm unique distribution partitioning

问题

我需要一个执行此操作的算法:

  

找到所有独特的方法来划分“桶”之间的给定总和而不关心订单

我希望我清楚合理地表达自己。

实施例

对于总和5和3桶,算法应该返回的是:

  

[5,0,0]
  [4,1,0]
  [3,2,0]
  [3,1,1]   [2,2,1]

声明

如果这个问题可能是一个骗局,我很抱歉,但我不确切地知道这些问题究竟是什么。尽管如此,我仍然使用我能想到的所有措辞在Google和SO上进行搜索,但只找到了以甚至方式分发的结果,而不是所有独特的方式。

6 个答案:

答案 0 :(得分:2)

比编写一篇5页的算法文章更容易编写几行代码。 想到的最简单的版本:

vector<int> ans;

void solve(int amount, int buckets, int max){
  if(amount <= 0) { printAnswer(); return;}
  if(amount > buckets * max) return; // we wont be able to fulfill this request anymore

  for(int i = max; i >= 1; i--){
    ans.push_back(i);
    solve(amount-i, buckets-1, i);
    ans.pop_back();
  } 
}

void printAnswer(){
  for(int i = 0; i < ans.size(); i++) printf("%d ", ans[i]);
  for(int i = 0; i < all_my_buckets - ans.size(); i++) printf("0 ");
  printf("\n");
}

它也值得改进,以便你像solve( amount-k*i, buckets-k, i-1)那样堆叠你的选择 - 所以你不会创造太深的复发。 (据我所知,堆栈的大小为O(sqrt(n))然后。

为什么没有动态编程?

我们不想找到所有这些可能性的数量,因此即使我们再次达到相同的点,我们也必须打印每一个数字,因此复杂性将保持不变。

我希望它对你有所帮助,随时问我任何问题

答案 1 :(得分:1)

Haskell中的某些内容依赖于this answer

import Data.List (nub, sort)

parts 0 = []
parts n = nub $ map sort $ [n] : [x:xs | x <- [1..n`div`2], xs <- parts(n - x)]

partitions n buckets = 
  let p = filter (\x -> length x <= buckets) $ parts n 
  in map (\x -> if length x == buckets then x else addZeros x) p  
    where addZeros xs = xs ++ replicate (buckets - length xs) 0


OUTPUT:
*Main> partitions 5 3
[[5,0,0],[1,4,0],[1,1,3],[1,2,2],[2,3,0]]

答案 2 :(得分:0)

一种完全不同的方法,但如果你不关心效率或优化,你总是可以使用旧的&#34;无桶&#34;分区算法。然后,您可以通过检查答案中的零数来过滤搜索。

例如,[1,1,1,1,1]会被忽略,因为它有超过3个存储桶,但[2,2,1,0,0]会通过。

答案 3 :(得分:0)

这称为整数分区。

Fast Integer Partition Algorithms是一篇综合性论文,描述了执行整数分区的所有最快算法。

答案 4 :(得分:0)

如果只有三个桶,这个wud是最简单的代码。

for(int i=0;i<=5;i++){
        for(int j=0;j<=5-i&&j<=i;j++){
            if(5-i-j<=i && 5-i-j<=j)
                System.out.println("["+i+","+j+","+(5-i-j)+"]");
        }
}

答案 5 :(得分:0)

在这里和其他人一起添加我的方法。它是用Python编写的,所以它实际上就像伪代码一样。

我的第一种方法有效,但效率非常低:

def intPart(buckets, balls):
    return uniqify(_intPart(buckets, balls))

def _intPart(buckets, balls):
    solutions = []

    # base case
    if buckets == 1:
        return [[balls]]

    # recursive strategy
    for i in range(balls + 1):
        for sol in _intPart(buckets - 1, balls - i):
            cur = [i]
            cur.extend(sol)
            solutions.append(cur)

    return solutions

def uniqify(seq):
    seen = set()
    sort = [list(reversed(sorted(elem))) for elem in seq]
    return [elem for elem in sort if str(elem) not in seen and not seen.add(str(elem))]

这是我的重写解决方案。它完全避免了使用max_变量跟踪前一个桶中的球来“统一”它的需要。这会对列表进行排序并防止任何欺骗:

def intPart(buckets, balls, max_ = None):
    # init vars
    sols = []
    if max_ is None:
        max_ = balls
    min_ = max(0, balls - max_)

    # assert stuff
    assert buckets >= 1
    assert balls >= 0

    # base cases
    if (buckets == 1):
        if balls <= max_:
            sols.append([balls])
    elif balls == 0:
        sol = [0] * buckets
        sols.append(sol)

    # recursive strategy
    else:
        for there in range(min_, balls + 1):
            here = balls - there
            ways = intPart(buckets - 1, there, here)
            for way in ways:
                sol = [here]
                sol.extend(way)
                sols.append(sol)

    return sols

为了全面,这是从Perl写的MJD中偷来的另一个答案:

#!/usr/bin/perl

sub part {
  my ($n, $b, $min) = @_;
  $min = 0 unless defined $min;

  # base case
  if ($b == 0) {
    if ($n == 0) { return ([]) }
    else         { return ()   }
  }

  my @partitions;
  for my $first ($min .. $n) {
    my @sub_partitions = part($n - $first, $b-1, $first);
    for my $sp (@sub_partitions) {
      push @partitions, [$first, @$sp];
    }
  }
  return @partitions;
}