繁体   English   中英

如何找到向量的两个子集和之间的最大和最小严格正差?

[英]How to find the maximal and minimal strictly positive difference between two subset sums of a vector?

我搜索了这个,但找不到任何似乎匹配的东西; 如果有人可以帮助或指出我正确的方向,那就太好了。

假设您有一个数值向量h = c(-1,-2,3,5,6,9) (我使用的是 R)。

您对该向量的 3 个元素进行了 2 个不同的选择。 您取每个选择的总和,然后取两个总和之间的差。
例如,一个选择可以是c(-1,3,5) --> 总和是 7; 另一个c(-2,3,9) --> 总和为 10; 差异是 10-7 = 3。

你要知道:

  • 最大可能(正)差异
  • 最小可能的差异

对于像这样的小向量,您可以使用蛮力,获得两个总和之间所有可能的差异,然后查找所需的值。

h = c(-1,-2,3,5,6,9)
N <- length(h)
n <- 3

vs <- expand.grid(rep(list(0:1),2*N))

vs["np1"] <- rowSums(vs[,1:N])
vs["np2"] <- rowSums(vs[,(N+1):(2*N)])

vs <- vs[(vs$np1 == n) & (vs$np2 == n),]

vs["hSum1"] <- apply(vs,1,function(x) sum(h*x[1:N]))
vs["hSum2"] <- apply(vs,1,function(x) sum(h*x[(N+1):(2*N)]))

vs["hdiff"] <- vs$hSum2-vs$hSum1

max(vs$hdiff)
#[1] 20
min(vs[vs$hdiff > 0,"hdiff"])
#[1] 1

显然,这对于较大的向量是不可能的。

我发现通过简单地对h (升序)进行排序并取其最后 3 个和前 3 个元素之间的差异可以找到最大的差异:

sum(sort(h)[(N-n+1):(N)]-sort(h)[1:n])
#[1] 20

但是,我无法找出最小差异的解决方案。
我尝试了线性规划,但我找不到将严格不等式强加于差异的技巧,这(我认为)是避免获得 0 作为解决方案所必需的。
从这个意义上说, 这篇文章在概念上看起来很接近,但我无法理解它,因为我看不到该方法的来源,并且当我在没有试图理解它的情况下应用它时,它不起作用.

有任何想法吗?

谢谢!


编辑- 找到最小正差的可能 LP 解决方案

通过迭代。
Dmin成为所寻求的差异。 我首先找到Dmin的上限,作为h唯一元素之间的最小成对差异:

h <- c(2.1,1,-0.5,0,1.7,2.3)
N <- length(h)
n <- 3

min.hdiff <- min(diff(sort(unique(h))))

UB <- min.hdiff
UB
#[1] 0.2

下限可以设置为 0:

LB <- 0

在这种情况下,很明显UB不是Dmin 可以通过蛮力检查Dmin为 0.1。

为了通过 LP 重现它,我首先定义了一个函数来查找LB 和 UB 之间包含最大(而不是最小差:

obj <- c(h,-h)

constr.n1 <- c(rep(1,N),rep(0,N))
constr.n2 <- c(rep(0,N),rep(1,N))
dir.n <- "=="
rhs.n <- n

constr.D <- c(h,-h)
dir.D1 <- ">="
rhs.D1 <- LB
dir.D2 <- "<="
rhs.D2 <- UB

mat <- rbind(constr.n1,constr.n2,constr.D,constr.D)
dir <- c(dir.n,dir.n,dir.D1,dir.D2)
rhs <- c(rhs.n,rhs.n,rhs.D1,rhs.D2)
N.rhs <- length(rhs)

require(Rsymphony)

DS.feas <- function(LB,UB) {
  rhs[c(N.rhs-1,N.rhs)] <- c(LB,UB)
  LP.sol <- Rsymphony_solve_LP(obj,mat,dir,rhs,types="B",max=T)
  if ((LP.sol$status == 0) & (LP.sol$objval > 0)) {return(list(1,LP.sol$solution,LP.sol$objval))} else {return(list(0,NULL,LP.sol$objval))}
}

然后我检查初始 [LB,UB] 是否可行:

LB.feas <- DS.feas(LB,UB)

LB.feas
#[[1]]
#[1] 1
#
#[[2]]
# [1] 0 1 0 1 0 1 1 1 0 1 0 0
#
#[[3]]
#[1] 0.2

由于当前[LB,UB]是可行的,在下一次迭代中,我测试LBUB ( MB ) 之间的中点作为新的推定UB

MB = (LB+UB)/2
MB
#[1] 0.1
MB.feas = DS.feas(LB,MB)
MB.feas
#[[1]]
#[1] 1
#
#[[2]]
# [1] 0 1 0 1 1 0 1 1 1 0 0 0
#
#[[3]]
#[1] 0.1

可行的。 所以我将UB设置为MB并测试新的、较低(但仍然为正)的中点:

UB = MB
MB = (LB+UB)/2
MB
[1] 0.05
MB.feas = DS.feas(LB,MB)
#MB.feas
#[[1]]
#[1] 0
#
#[[2]]
#NULL
#
#[[3]]
#[1] 0

不可行。 所以Dmin必须在当前MBUB 我将LB设置为MB并运行下一次迭代。

依此类推,直到达到收敛。

我在各种载体上对此进行了测试。
它似乎有效; 只是,对于N = 20 ,它已经变得非常慢了。

如果有人可以建议如何更好地做到这一点......

我不知道 r,但我确定您可以制定与此 python 解决方案相同的问题:

from pulp import *

vals = [-1,-2,3,5,6,9]
r = range(0, len(vals))

#group1[i] = 1 if we use vals[i] in first group
group1 = LpVariable.dicts('group1', r, cat='Binary')
group2 = LpVariable.dicts('group2', r, cat='Binary')

#repeats[i] = 1 if we allow to use vals[i] in both groups
repeats =  LpVariable.dicts('repeats', r, cat='Binary')

prob = LpProblem('test', LpMinimize)

sum1 = lpSum([group1[i] * vals[i] for i in r])
sum2 = lpSum([group2[i] * vals[i] for i in r])

#objective
prob += sum1 - sum2

#make group1 be highest sum to prevent negative solutions
prob += sum1 >= sum2

#make each group have 3 items
prob += lpSum([group1[i] for i in r]) == 3
prob += lpSum([group2[i] for i in r]) == 3


#dont allow choosing same number for both groups if we are not allowing repeat
for i in r:
    prob += group1[i] + group2[i] <= repeats[i] + 1

#only allow up to 2 repeats (thus preventing same solution repeating 3)
prob += lpSum([repeats[i] for i in r]) <= 2

prob.solve()

print([vals[x] for x in r if group1[x].value()], [vals[x] for x in r if group2[x].value()])

编辑:只需重新阅读您的问题,似乎您不想允许解决方案 0。在这种情况下,它更容易,可以删除与重复相关的所有内容,只需将第一个限制更改为:

#avoid solution 0
prob += sum1 - sum2 >= 1 

最小的区别其实是分区问题https://en.wikipedia.org/wiki/Partition_problem

最大的差异是一个子集中的所有负数和另一个子集中的正数

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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