多路分区的变化

Posted

技术标签:

【中文标题】多路分区的变化【英文标题】: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 完全问题,但我不需要一个精确的解决方案,只是一个粗略的近似。感谢任何帮助,因为我找不到任何接近我需要的东西,除了多路分区问题,这里不能完全使用。

谢谢。

【问题讨论】:

【参考方案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;

【讨论】:

以上是关于多路分区的变化的主要内容,如果未能解决你的问题,请参考以下文章

根据列值的变化对pyspark数据框进行分区

partprobe

Android8.0后版本的分区变化

数据系统分区设计 - 请求路由

Kafka-分区分配策略

数据系统分区设计 - 请求路由