【问题标题】:Variation of the multiway partition多路分区的变化
【发布时间】:2018-05-09 17:44:22
【问题描述】:

我一直在从事一些项目,偶然发现了一个问题,它是多路分区问题的变体。我们可以将问题表述如下:

给定一个由 n 个整数组成的集合 S,以及一个由 k 个和组成的集合 K,求 >kS 的子集,使得第 i 个子集具有 K 的第 i 个元素的和。

这并不严格要求对集合 S 进行分区,因为某些元素可能未被使用。

我的天真尝试是首先遍历 S 的元素,如果该元素与某些总和匹配,则形成一个单元素子集。然后我会按升序对 S 的元素进行排序,并对元素求和,直到它们达到给定的总和(子集总和问题)。但是,这经常失败。

解决方案不必是准确的。问题的性质允许每个总和的误差高达 10%。但是,它必须相当快。为了提供有关输入数据的一些信息,n 预计约为数百万,而 k 预计在 1 到 10000 之间。该算法应该在 10 秒的范围内运行(它将在 Web 界面上使用,用户不应等待超过一两分钟)。

如果我没记错的话,这是一个 NP 完全问题,但我不需要一个精确的解决方案,只是一个粗略的近似。感谢任何帮助,因为我找不到任何接近我需要的东西,除了多路分区问题,这里不能完全使用。

谢谢。

【问题讨论】:

    标签: algorithm language-agnostic partitioning


    【解决方案1】:

    我知道这个问题很老,但我发现这段代码做的事情非常相似(它是针对集合的精确 N 总和)。

    https://github.com/ephemerant/poe-vendor-optimizer/blob/master/functions.js

    它在 javascript 中,但可以适应其他语言,在我的情况下,我已将其更改为 java。只需要为递归调用做一个新的 ArrayList(_a) 否则它会在不同的递归之间改变同一个 List。

    这只会做一组给定的 N,你必须在循环中调用它,直到它返回一个空列表(意味着没有确切的 N 总和)

    function smallest(N, A) {
      var n = sum(A);  // Largest possible result
      var a = A;       // Largest possible array
    
      if (N <= 0 || n < N)  // Is it impossible?
        return [];
    
      for (var i = 0; i < A.length; i++) {
        if (n == N)  // Are we already perfect?
          return a;
    
        var x = A[i];  // Element in A
    
        var _a = A.slice(i + 1);  // Subarray to the right of x
    
        _a = smallest(N - x.quality, _a);  // Recurse
        _a.unshift(x);             // Add x to beginning
    
        var _n = sum(_a);  // Sum of the subarray
    
        if (_n < n && _n >= N) {  // Is this subarray better?
          n = _n;
          a = _a;
        }
      }
    

    这是我的 Java 代码:

    private List<SkillGem> smallest(int N, List<SkillGem> A) {
        int n = A.stream().mapToInt(SkillGem::getQuality).sum(); // Largest possible result
        List<SkillGem> a = A; // Largest possible array
        if(N <= 0 || n < N) return new ArrayList<>(); // Is it impossible?
    
        for (int i = 0; i < A.size(); i++) {
            if (n == N)  // Are we already perfect?
                return a;
            if(i+1 > A.size()) return new ArrayList<>();
    
            SkillGem x = A.get(i); // Element in A
            List<SkillGem> _a = A.subList(i+1, A.size()); // Subarray to the right of x
            _a = smallest(N - x.getQuality(), new ArrayList<>(_a));  // Recurse
            _a.add(0, x); // Add x to beginning
    
            int _n = _a.stream().mapToInt(SkillGem::getQuality).sum();  // Sum of the subarray
    
            if (_n < n && _n >= N) {  // Is this subarray better?
                n = _n;
                a = _a;
            }
        }
        return a;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-07-27
      • 1970-01-01
      • 1970-01-01
      • 2022-01-08
      • 2016-02-22
      • 1970-01-01
      • 2017-04-23
      • 1970-01-01
      相关资源
      最近更新 更多