繁体   English   中英

查找可以服务我所有项目的最小节点数

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM