Java [a] a, b ============== [a] [a, b] [b]
如果输入为Java [a] a, b ============== [a] [a, b] [b],java,algorithm,optimization,knapsack-problem,Java,Algorithm,Optimization,Knapsack Problem,如果输入为a,b,则有3种可能的结果:[a],[b],[a,b] 这就是我们发现规则1的地方:单个元素([a])的可能性是a,b中可能性的子集。或广义: 前面结果中的所有可能性都将包含在当前结果中 让我们看看这是否适用于a,b,c: a, b a, b, c ================== ============================= --------------
a,b
,则有3种可能的结果:[a],[b],[a,b]
这就是我们发现规则1的地方:单个元素([a]
)的可能性是a,b
中可能性的子集。或广义:
前面结果中的所有可能性都将包含在当前结果中
让我们看看这是否适用于a,b,c
:
a, b a, b, c
================== =============================
-------------- -------------
| [a] [a, b] | | [a] [a, b] |
| [b] | | [b] |
|--------------| |-------------| [a, b, c]
[c] [a, c]
[b, c]
a, b, c
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
您可以为更大的输入验证这一点,但它始终是正确的。如果你从正确的角度来看,这一切都是有意义的。潜在n
的所有组合将是:所有n-1
+的组合
但这里还有一条更有趣的规则 如果您有这样的输入:
a, b
==============
[a] [a, b]
[b]
您可以创建一个关于如何计算下一个的算法。首先,创建上一个的副本(根据上述规则):
对于第一行,您只需添加“最后一个”下一个字母。由于下一行是a、b、c
,因此需要添加到第一行的内容是:c
:
a, b a, b, c
================== =============================
-------------- -------------
| [a] [a, b] | | [a] [a, b] |
| [b] | | [b] |
|--------------| |-------------| [a, b, c]
[c] [a, c]
[b, c]
a, b, c
==============
[a] [a, b]
[b]
[c]
a, b, c
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
对于第二行,取上一行(减去添加的c
),添加“最后一个”下一个字母并插入它。即:
a, b, c
===================
[a] <-| [a, b]
[b] |-> [a, c] <-- "a" came from the previous row, "c" was added as the last one
[c]
对于最后一行,我们只需添加所有“下一行”(a、b、c
):
使用上述相同的逻辑,您可以计算a、b、c、d的结果:
先拷贝:
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
添加d
:
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
[d]
获取上一行并附加:
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
[d] [a, d]
[b, d]
[c, d]
同样,取上一行并追加(记住:“除了添加的那一行”):
如果您理解上面所发生的事情,那么这一切都是关于编写代码的。我所做的唯一更改不是添加我已经知道将无法通过对max
检查的元素。在这里,它看起来很复杂,但实际上它相当简单(除了一些边缘情况):
静态列表分区(列出所有分区,int max){
ArrayList previousResult=新ArrayList();
ArrayList currentResult=新的ArrayList();
int i=0;
对于(;i 1){
对于(int j=0;j x.getKey()x.stream().map(y->(ArrayList)y.clone()).collect(Collectors.toCollection(ArrayList::new)))
.collect(收集器.toCollection(ArrayList::new));
}
私有静态布尔值(列表中,int max){
在.stream().mapToInt(Choice::getCost.sum()中返回如果你知道这是计算机科学中最著名的问题之一的变种,那么它可能会帮助你研究算法。你为什么不从高到低排序?@Jordan Knapsack有两个变量:使用整数权重约束使值最大化。我在这里看不到与权重约束等价的东西。@jrook想象一个例子,在这个例子中er有100美元,物品的价格分别为80美元、50美元和40美元。从高到低排序会导致购买80美元的物品,剩余20美元。但最佳解决方案是同时购买50美元和40美元的物品,剩余10美元未用。因此,从高到低排序并不总是产生最佳解决方案。同样,尝试从低到高排序gh加上$20、60和$90,你会发现它也不是最优的。这是子集和问题的优化形式。行sortedResult.entrySet().removeIf(key->key.getKey()!=getMapKey);
正在对Integer
对象执行引用比较,而不是比较它们的值。但无论如何,这是一个奇怪的操作。一个映射中只能出现一个键,因此这会删除除一个键以外的所有键。但是,通过qualifyItemsCombinationList.get(0)排序后,最小的项已经可用
,无需将列表复制到LinkedHashMap
。事实上,即使排序也已过时,Collections.min(qualifyItems组合,Entry.comparingByKey())
已经给出了最小的条目……这是一个有趣的解决方案,但更有趣的是,这给我带来了多少关于在国内举办电脑奥运会的记忆。令人震惊。
a, b, c
===================
[a] [a, b]
[b] <-| [a, c]
[c] |-> [b, c] <-- "b" came from the previous row, "c" then added as the last one
a, b, c
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
[d]
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c]
[d] [a, d]
[b, d]
[c, d]
a, b, c, d
=================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c] [a, b, d] <--- [a, b] + [d]
[d] [a, d] [a, c, d] <--- [a, c] + [d]
[b, d] [b, c, d] <--- [b, c] + [d]
[c, d]
a, b, c, d
=================================================
[a] [a, b]
[b] [a, c] [a, b, c]
[c] [b, c] [a, b, d]
[d] [a, d] [a, c, d] [a, b, c, d]
[b, d] [b, c, d]
[c, d]
static List<String> partitions(List<Choice> all, int max) {
ArrayList<ArrayList<ArrayList<Choice>>> previousResult = new ArrayList<>();
ArrayList<ArrayList<ArrayList<Choice>>> currentResult = new ArrayList<>();
int i = 0;
for(;i<all.size();++i) {
// add the first element
Choice current = all.get(i);
if(currentResult.isEmpty()) {
if(less(List.of(current), max)) {
// looks complicated, but all it does is adds a single element in the first index
ArrayList<Choice> inner = new ArrayList<>();
inner.add(current);
ArrayList<ArrayList<Choice>> in = new ArrayList<>();
in.add(inner);
currentResult.add(in);
previousResult.add(in);
}
} else {
if(less(List.of(current), max)) {
ArrayList<Choice> element = new ArrayList<>();
element.add(current);
currentResult.get(0).add(element);
}
if(currentResult.size() > 1) {
for(int j=0;j<i-1;++j) {
if(j < previousResult.size()) {
ArrayList<ArrayList<Choice>> p = previousResult.get(j);
for(int d=0;d<=p.size()-1;++d){
ArrayList<Choice> copy = new ArrayList<>(p.get(d));
copy.add(all.get(i));
if(less(copy, max)){
currentResult.get(j).add(copy);
}
}
}
}
}
// add tail if possible
ArrayList<ArrayList<Choice>> tail = new ArrayList<>();
ArrayList<Choice> t = new ArrayList<>(all.subList(0, i + 1));
if(less(t, max)) {
tail.add(t);
currentResult.add(tail);
}
if(currentResult.size() == 1) {
ArrayList<Choice> l = currentResult.get(0).stream().flatMap(List::stream).collect(Collectors.toCollection(ArrayList::new));
if(less(l, max)) {
tail.add(l);
currentResult.add(tail);
}
}
// smart copy here
previousResult = copy(previousResult, currentResult);
}
}
return
currentResult.stream()
.flatMap(List::stream)
.map(list -> {
int sum = list.stream().mapToInt(Choice::getCost).sum();
List<String> l = list.stream().map(Choice::getKey).collect(Collectors.toList());
return new AbstractMap.SimpleEntry<>(sum, l);
})
.sorted(Map.Entry.<Integer, List<String>>comparingByKey().reversed())
.filter(x -> x.getKey() <= max)
.map(Map.Entry::getValue)
.findFirst()
.orElse(List.of());
}
private static ArrayList<ArrayList<ArrayList<Choice>>> copy(ArrayList<ArrayList<ArrayList<Choice>>> previousResult, ArrayList<ArrayList<ArrayList<Choice>>> currentResult) {
return currentResult.stream()
.map(x -> x.stream().map(y -> (ArrayList<Choice>)y.clone()).collect(Collectors.toCollection(ArrayList::new)))
.collect(Collectors.toCollection(ArrayList::new));
}
private static boolean less(List<Choice> in, int max) {
return in.stream().mapToInt(Choice::getCost).sum() <= max;
}