[英]Find minimum number of nodes that can serve all my items
我有一些商店和一些物品,并且我想从商店的最小数量中运送所有物品。
对于Exm:
我有3家商店(s1,s2,s3)和4个商品(p1,p2,p3,p4)。
这些商店有我的项目集的任何子集。
对于Exm。
s1具有(p1,p3);
s2具有(p2,p4);
s3具有(p2,p3,p4);
因此,可以提供我所有商品的最低商店是:
(S1,S3)。
我已尽力检查商店的所有可能组合并找到最低限度的商品。 但是要花很多时间
public static void main(String[] args) {
Map<String, Set<String>> buckets = new HashMap<>();
buckets.putIfAbsent("s1", new HashSet<>());
buckets.putIfAbsent("s2", new HashSet<>());
buckets.putIfAbsent("s3", new HashSet<>());
buckets.get("s1").add("p1");
buckets.get("s1").add("p3");
buckets.get("s2").add("p2");
buckets.get("s2").add("p4");
buckets.get("s3").add("p2");
buckets.get("s3").add("p3");
buckets.get("s3").add("p4");
Set<String> allsku = new HashSet<>();
for (String node : buckets.keySet()) {
allsku.addAll(buckets.get(node));
}
Long val = System.currentTimeMillis();
Set<String> result = getBestCmnm(buckets, new HashSet<>(), allsku);
System.out.println(result + " " + (System.currentTimeMillis() - val));
}
static Set<String> getBestCmnm(Map<String, Set<String>> buckets, Set<String> choosedNode, Set<String> remainingSku) {
if (remainingSku.size() == 0) {
return choosedNode;
}
Set<String> result = new HashSet<>();
Set<String> presentNode = new HashSet<>(buckets.keySet());
presentNode.removeAll(choosedNode);
int min = Integer.MAX_VALUE;
for (String node : presentNode) {
if (containAny(buckets.get(node), remainingSku)) {
Set<String> choosedNode1 = new HashSet<>(choosedNode);
choosedNode1.add(node);
Set<String> remainingSku1 = new HashSet<>(remainingSku);
remainingSku1.removeAll(buckets.get(node));
Set<String> val = getBestCmnm(buckets, choosedNode1, remainingSku1);
if (val.size() < min) {
min = val.size();
result = val;
}
}
}
return result;
}
private static boolean containAny(Set<String> from, Set<String> to) {
for (String f : to) {
if (from.contains(f)) {
return true;
}
}
return false;
}
这是集合覆盖问题 ,与“顶点覆盖问题”同构。 我见过的所有解决方案都使用一个矩阵来表示,该矩阵可以设置哪些项目:
p1 p2 p3 p4
s1 x - x -
s2 - x - x
s3 - x x x
首先,请注意您有两种最佳解决方案:(s1,s2)和(s1,s3)。 如果您要进行其他优化,以使所有集合大小的总和最小化(作为多个最小集数解决方案之间的决胜局),那么您将面临更大的问题。
扫描解决方案时,请注意“贪婪算法”。 这是最容易解释的算法,算法复杂度很高,并且给出了很好的近似值-但是证明次优是微不足道的。
通过选择覆盖最大数量产品的集合来衡量“贪婪”。 然后,从问题空间中删除该集合和那些产品,然后重试剩余的问题。
就您而言,这是微不足道的: s3
涵盖最多-3种产品。 您将s3
放入解决方案集中,从需求中删除p2 p3 p4
,现在剩下的是2x1矩阵:
p1
s1 x
s2 -
这给出了解{s1, s3}
。
预处理
对于获得的任何输入,请确保通过一些简单的预处理来减小问题的大小。 除非您也需要进行次要优化(最少数量),否则请查找子集:删除作为另一个子集的任何集合。
最重要的是,在每个阶段,您都将(作为解决方案的一部分)采用任何产品的唯一集合。 在您发布的示例中,您将立即将s1
放入解决方案中,因为它是p1
的唯一提供者。 这也会从问题空间中删除p3
,让您
p2 p4
s2 x x
s3 x x
...并且任何一家供应商都可以解决问题。
一旦每种剩余产品都达到了多个供应商的地步,便进入启发式领域。 我还没有找到一种非常好的解决方案的参考; 它使用智能回溯。
计算每种产品的供应商数量,并找到最低数量。 在此最小集合中选择一种产品。 遍历此产品的供应商(以贪心的顺序排序可能会有所帮助),然后依次选择每个产品作为此产品的供应商。 从问题空间中删除供应商和产品,然后再次发生。
首先进行此操作。 跟踪迄今为止找到的最佳解决方案; 在回溯中将其作为参数传递,因此您也可以砍掉任何与现有解决方案深度不相等的分支。
我希望这能使您迈向一个好的解决方案。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.