多路分区的变化
Posted
技术标签:
【中文标题】多路分区的变化【英文标题】:Variation of the multiway partition 【发布时间】:2018-05-09 17:44:22 【问题描述】:我一直在从事一些项目,偶然发现了一个问题,它是多路分区问题的变体。我们可以将问题表述如下:
给定一个由 n 个整数组成的集合 S,以及一个由 k 个和组成的集合 K,求 >k 个 S 的子集,使得第 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;
【讨论】:
以上是关于多路分区的变化的主要内容,如果未能解决你的问题,请参考以下文章