我需要一个执行此操作的算法:
找到所有独特的方法来划分“桶”之间的给定总和而不关心订单
我希望我清楚合理地表达自己。
对于总和5和3桶,算法应该返回的是:
[5,0,0]
[4,1,0]
[3,2,0]
[3,1,1] [2,2,1]
如果这个问题可能是一个骗局,我很抱歉,但我不确切地知道这些问题究竟是什么。尽管如此,我仍然使用我能想到的所有措辞在Google和SO上进行搜索,但只找到了以甚至方式分发的结果,而不是所有独特的方式。
答案 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;
}